validate.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. package dsig
  2. import (
  3. "bytes"
  4. "crypto/rsa"
  5. "crypto/x509"
  6. "encoding/base64"
  7. "errors"
  8. "fmt"
  9. "regexp"
  10. "github.com/beevik/etree"
  11. "github.com/russellhaering/goxmldsig/etreeutils"
  12. "github.com/russellhaering/goxmldsig/types"
  13. )
  14. var uriRegexp = regexp.MustCompile("^#[a-zA-Z_][\\w.-]*$")
  15. var whiteSpace = regexp.MustCompile("\\s+")
  16. var (
  17. // ErrMissingSignature indicates that no enveloped signature was found referencing
  18. // the top level element passed for signature verification.
  19. ErrMissingSignature = errors.New("Missing signature referencing the top-level element")
  20. )
  21. type ValidationContext struct {
  22. CertificateStore X509CertificateStore
  23. IdAttribute string
  24. Clock *Clock
  25. }
  26. func NewDefaultValidationContext(certificateStore X509CertificateStore) *ValidationContext {
  27. return &ValidationContext{
  28. CertificateStore: certificateStore,
  29. IdAttribute: DefaultIdAttr,
  30. }
  31. }
  32. // TODO(russell_h): More flexible namespace support. This might barely work.
  33. func inNamespace(el *etree.Element, ns string) bool {
  34. for _, attr := range el.Attr {
  35. if attr.Value == ns {
  36. if attr.Space == "" && attr.Key == "xmlns" {
  37. return el.Space == ""
  38. } else if attr.Space == "xmlns" {
  39. return el.Space == attr.Key
  40. }
  41. }
  42. }
  43. return false
  44. }
  45. func childPath(space, tag string) string {
  46. if space == "" {
  47. return "./" + tag
  48. } else {
  49. return "./" + space + ":" + tag
  50. }
  51. }
  52. func mapPathToElement(tree, el *etree.Element) []int {
  53. for i, child := range tree.Child {
  54. if child == el {
  55. return []int{i}
  56. }
  57. }
  58. for i, child := range tree.Child {
  59. if childElement, ok := child.(*etree.Element); ok {
  60. childPath := mapPathToElement(childElement, el)
  61. if childElement != nil {
  62. return append([]int{i}, childPath...)
  63. }
  64. }
  65. }
  66. return nil
  67. }
  68. func removeElementAtPath(el *etree.Element, path []int) bool {
  69. if len(path) == 0 {
  70. return false
  71. }
  72. if len(el.Child) <= path[0] {
  73. return false
  74. }
  75. childElement, ok := el.Child[path[0]].(*etree.Element)
  76. if !ok {
  77. return false
  78. }
  79. if len(path) == 1 {
  80. el.RemoveChild(childElement)
  81. return true
  82. }
  83. return removeElementAtPath(childElement, path[1:])
  84. }
  85. // Transform returns a new element equivalent to the passed root el, but with
  86. // the set of transformations described by the ref applied.
  87. //
  88. // The functionality of transform is currently very limited and purpose-specific.
  89. func (ctx *ValidationContext) transform(
  90. el *etree.Element,
  91. sig *types.Signature,
  92. ref *types.Reference) (*etree.Element, Canonicalizer, error) {
  93. transforms := ref.Transforms.Transforms
  94. if len(transforms) != 2 {
  95. return nil, nil, errors.New("Expected Enveloped and C14N transforms")
  96. }
  97. // map the path to the passed signature relative to the passed root, in
  98. // order to enable removal of the signature by an enveloped signature
  99. // transform
  100. signaturePath := mapPathToElement(el, sig.UnderlyingElement())
  101. // make a copy of the passed root
  102. el = el.Copy()
  103. var canonicalizer Canonicalizer
  104. for _, transform := range transforms {
  105. algo := transform.Algorithm
  106. switch AlgorithmID(algo) {
  107. case EnvelopedSignatureAltorithmId:
  108. if !removeElementAtPath(el, signaturePath) {
  109. return nil, nil, errors.New("Error applying canonicalization transform: Signature not found")
  110. }
  111. case CanonicalXML10ExclusiveAlgorithmId:
  112. var prefixList string
  113. if transform.InclusiveNamespaces != nil {
  114. prefixList = transform.InclusiveNamespaces.PrefixList
  115. }
  116. canonicalizer = MakeC14N10ExclusiveCanonicalizerWithPrefixList(prefixList)
  117. case CanonicalXML11AlgorithmId:
  118. canonicalizer = MakeC14N11Canonicalizer()
  119. case CanonicalXML10RecAlgorithmId:
  120. canonicalizer = MakeC14N10RecCanonicalizer()
  121. case CanonicalXML10CommentAlgorithmId:
  122. canonicalizer = MakeC14N10CommentCanonicalizer()
  123. default:
  124. return nil, nil, errors.New("Unknown Transform Algorithm: " + algo)
  125. }
  126. }
  127. if canonicalizer == nil {
  128. return nil, nil, errors.New("Expected canonicalization transform")
  129. }
  130. return el, canonicalizer, nil
  131. }
  132. func (ctx *ValidationContext) digest(el *etree.Element, digestAlgorithmId string, canonicalizer Canonicalizer) ([]byte, error) {
  133. data, err := canonicalizer.Canonicalize(el)
  134. if err != nil {
  135. return nil, err
  136. }
  137. digestAlgorithm, ok := digestAlgorithmsByIdentifier[digestAlgorithmId]
  138. if !ok {
  139. return nil, errors.New("Unknown digest algorithm: " + digestAlgorithmId)
  140. }
  141. hash := digestAlgorithm.New()
  142. _, err = hash.Write(data)
  143. if err != nil {
  144. return nil, err
  145. }
  146. return hash.Sum(nil), nil
  147. }
  148. func (ctx *ValidationContext) verifySignedInfo(sig *types.Signature, canonicalizer Canonicalizer, signatureMethodId string, cert *x509.Certificate, decodedSignature []byte) error {
  149. signatureElement := sig.UnderlyingElement()
  150. nsCtx, err := etreeutils.NSBuildParentContext(signatureElement)
  151. if err != nil {
  152. return err
  153. }
  154. signedInfo, err := etreeutils.NSFindOneChildCtx(nsCtx, signatureElement, Namespace, SignedInfoTag)
  155. if err != nil {
  156. return err
  157. }
  158. if signedInfo == nil {
  159. return errors.New("Missing SignedInfo")
  160. }
  161. // Canonicalize the xml
  162. canonical, err := canonicalSerialize(signedInfo)
  163. if err != nil {
  164. return err
  165. }
  166. signatureAlgorithm, ok := signatureMethodsByIdentifier[signatureMethodId]
  167. if !ok {
  168. return errors.New("Unknown signature method: " + signatureMethodId)
  169. }
  170. hash := signatureAlgorithm.New()
  171. _, err = hash.Write(canonical)
  172. if err != nil {
  173. return err
  174. }
  175. hashed := hash.Sum(nil)
  176. pubKey, ok := cert.PublicKey.(*rsa.PublicKey)
  177. if !ok {
  178. return errors.New("Invalid public key")
  179. }
  180. // Verify that the private key matching the public key from the cert was what was used to sign the 'SignedInfo' and produce the 'SignatureValue'
  181. err = rsa.VerifyPKCS1v15(pubKey, signatureAlgorithm, hashed[:], decodedSignature)
  182. if err != nil {
  183. return err
  184. }
  185. return nil
  186. }
  187. func (ctx *ValidationContext) validateSignature(el *etree.Element, sig *types.Signature, cert *x509.Certificate) (*etree.Element, error) {
  188. idAttr := el.SelectAttr(ctx.IdAttribute)
  189. if idAttr == nil || idAttr.Value == "" {
  190. return nil, errors.New("Missing ID attribute")
  191. }
  192. var ref *types.Reference
  193. // Find the first reference which references the top-level element
  194. for _, _ref := range sig.SignedInfo.References {
  195. if _ref.URI == "" || _ref.URI[1:] == idAttr.Value {
  196. ref = &_ref
  197. }
  198. }
  199. // Perform all transformations listed in the 'SignedInfo'
  200. // Basically, this means removing the 'SignedInfo'
  201. transformed, canonicalizer, err := ctx.transform(el, sig, ref)
  202. if err != nil {
  203. return nil, err
  204. }
  205. digestAlgorithm := ref.DigestAlgo.Algorithm
  206. // Digest the transformed XML and compare it to the 'DigestValue' from the 'SignedInfo'
  207. digest, err := ctx.digest(transformed, digestAlgorithm, canonicalizer)
  208. if err != nil {
  209. return nil, err
  210. }
  211. decodedDigestValue, err := base64.StdEncoding.DecodeString(ref.DigestValue)
  212. if err != nil {
  213. return nil, err
  214. }
  215. if !bytes.Equal(digest, decodedDigestValue) {
  216. return nil, errors.New("Signature could not be verified")
  217. }
  218. // Decode the 'SignatureValue' so we can compare against it
  219. decodedSignature, err := base64.StdEncoding.DecodeString(sig.SignatureValue.Data)
  220. if err != nil {
  221. return nil, errors.New("Could not decode signature")
  222. }
  223. // Actually verify the 'SignedInfo' was signed by a trusted source
  224. signatureMethod := sig.SignedInfo.SignatureMethod.Algorithm
  225. err = ctx.verifySignedInfo(sig, canonicalizer, signatureMethod, cert, decodedSignature)
  226. if err != nil {
  227. return nil, err
  228. }
  229. return transformed, nil
  230. }
  231. func contains(roots []*x509.Certificate, cert *x509.Certificate) bool {
  232. for _, root := range roots {
  233. if root.Equal(cert) {
  234. return true
  235. }
  236. }
  237. return false
  238. }
  239. // findSignature searches for a Signature element referencing the passed root element.
  240. func (ctx *ValidationContext) findSignature(el *etree.Element) (*types.Signature, error) {
  241. idAttr := el.SelectAttr(ctx.IdAttribute)
  242. if idAttr == nil || idAttr.Value == "" {
  243. return nil, errors.New("Missing ID attribute")
  244. }
  245. var sig *types.Signature
  246. // Traverse the tree looking for a Signature element
  247. err := etreeutils.NSFindIterate(el, Namespace, SignatureTag, func(ctx etreeutils.NSContext, el *etree.Element) error {
  248. found := false
  249. err := etreeutils.NSFindChildrenIterateCtx(ctx, el, Namespace, SignedInfoTag,
  250. func(ctx etreeutils.NSContext, signedInfo *etree.Element) error {
  251. detachedSignedInfo, err := etreeutils.NSDetatch(ctx, signedInfo)
  252. if err != nil {
  253. return err
  254. }
  255. c14NMethod, err := etreeutils.NSFindOneChildCtx(ctx, detachedSignedInfo, Namespace, CanonicalizationMethodTag)
  256. if err != nil {
  257. return err
  258. }
  259. if c14NMethod == nil {
  260. return errors.New("missing CanonicalizationMethod on Signature")
  261. }
  262. c14NAlgorithm := c14NMethod.SelectAttrValue(AlgorithmAttr, "")
  263. var canonicalSignedInfo *etree.Element
  264. switch AlgorithmID(c14NAlgorithm) {
  265. case CanonicalXML10ExclusiveAlgorithmId:
  266. err := etreeutils.TransformExcC14n(detachedSignedInfo, "")
  267. if err != nil {
  268. return err
  269. }
  270. // NOTE: TransformExcC14n transforms the element in-place,
  271. // while canonicalPrep isn't meant to. Once we standardize
  272. // this behavior we can drop this, as well as the adding and
  273. // removing of elements below.
  274. canonicalSignedInfo = detachedSignedInfo
  275. case CanonicalXML11AlgorithmId:
  276. canonicalSignedInfo = canonicalPrep(detachedSignedInfo, map[string]struct{}{})
  277. case CanonicalXML10RecAlgorithmId:
  278. canonicalSignedInfo = canonicalPrep(detachedSignedInfo, map[string]struct{}{})
  279. case CanonicalXML10CommentAlgorithmId:
  280. canonicalSignedInfo = canonicalPrep(detachedSignedInfo, map[string]struct{}{})
  281. default:
  282. return fmt.Errorf("invalid CanonicalizationMethod on Signature: %s", c14NAlgorithm)
  283. }
  284. el.RemoveChild(signedInfo)
  285. el.AddChild(canonicalSignedInfo)
  286. found = true
  287. return etreeutils.ErrTraversalHalted
  288. })
  289. if err != nil {
  290. return err
  291. }
  292. if !found {
  293. return errors.New("Missing SignedInfo")
  294. }
  295. // Unmarshal the signature into a structured Signature type
  296. _sig := &types.Signature{}
  297. err = etreeutils.NSUnmarshalElement(ctx, el, _sig)
  298. if err != nil {
  299. return err
  300. }
  301. // Traverse references in the signature to determine whether it has at least
  302. // one reference to the top level element. If so, conclude the search.
  303. for _, ref := range _sig.SignedInfo.References {
  304. if ref.URI == "" || ref.URI[1:] == idAttr.Value {
  305. sig = _sig
  306. return etreeutils.ErrTraversalHalted
  307. }
  308. }
  309. return nil
  310. })
  311. if err != nil {
  312. return nil, err
  313. }
  314. if sig == nil {
  315. return nil, ErrMissingSignature
  316. }
  317. return sig, nil
  318. }
  319. func (ctx *ValidationContext) verifyCertificate(sig *types.Signature) (*x509.Certificate, error) {
  320. now := ctx.Clock.Now()
  321. roots, err := ctx.CertificateStore.Certificates()
  322. if err != nil {
  323. return nil, err
  324. }
  325. var cert *x509.Certificate
  326. if sig.KeyInfo != nil {
  327. // If the Signature includes KeyInfo, extract the certificate from there
  328. if len(sig.KeyInfo.X509Data.X509Certificates) == 0 || sig.KeyInfo.X509Data.X509Certificates[0].Data == "" {
  329. return nil, errors.New("missing X509Certificate within KeyInfo")
  330. }
  331. certData, err := base64.StdEncoding.DecodeString(
  332. whiteSpace.ReplaceAllString(sig.KeyInfo.X509Data.X509Certificates[0].Data, ""))
  333. if err != nil {
  334. return nil, errors.New("Failed to parse certificate")
  335. }
  336. cert, err = x509.ParseCertificate(certData)
  337. if err != nil {
  338. return nil, err
  339. }
  340. } else {
  341. // If the Signature doesn't have KeyInfo, Use the root certificate if there is only one
  342. if len(roots) == 1 {
  343. cert = roots[0]
  344. } else {
  345. return nil, errors.New("Missing x509 Element")
  346. }
  347. }
  348. // Verify that the certificate is one we trust
  349. if !contains(roots, cert) {
  350. return nil, errors.New("Could not verify certificate against trusted certs")
  351. }
  352. if now.Before(cert.NotBefore) || now.After(cert.NotAfter) {
  353. return nil, errors.New("Cert is not valid at this time")
  354. }
  355. return cert, nil
  356. }
  357. // Validate verifies that the passed element contains a valid enveloped signature
  358. // matching a currently-valid certificate in the context's CertificateStore.
  359. func (ctx *ValidationContext) Validate(el *etree.Element) (*etree.Element, error) {
  360. // Make a copy of the element to avoid mutating the one we were passed.
  361. el = el.Copy()
  362. sig, err := ctx.findSignature(el)
  363. if err != nil {
  364. return nil, err
  365. }
  366. cert, err := ctx.verifyCertificate(sig)
  367. if err != nil {
  368. return nil, err
  369. }
  370. return ctx.validateSignature(el, sig, cert)
  371. }