| // Copyright 2009 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // Package x509 parses X.509-encoded keys and certificates. |
| // |
| // On UNIX systems the environment variables SSL_CERT_FILE and SSL_CERT_DIR |
| // can be used to override the system default locations for the SSL certificate |
| // file and SSL certificate files directory, respectively. |
| package x509 |
| |
| import ( |
| "bytes" |
| "crypto" |
| "crypto/dsa" |
| "crypto/ecdsa" |
| "crypto/elliptic" |
| "crypto/rsa" |
| _ "crypto/sha1" |
| _ "crypto/sha256" |
| _ "crypto/sha512" |
| "crypto/x509/pkix" |
| "encoding/asn1" |
| "encoding/pem" |
| "errors" |
| "fmt" |
| "io" |
| "math/big" |
| "net" |
| "net/url" |
| "strconv" |
| "strings" |
| "time" |
| "unicode/utf8" |
| |
| "golang_org/x/crypto/cryptobyte" |
| cryptobyte_asn1 "golang_org/x/crypto/cryptobyte/asn1" |
| ) |
| |
| // pkixPublicKey reflects a PKIX public key structure. See SubjectPublicKeyInfo |
| // in RFC 3280. |
| type pkixPublicKey struct { |
| Algo pkix.AlgorithmIdentifier |
| BitString asn1.BitString |
| } |
| |
| // ParsePKIXPublicKey parses a DER encoded public key. These values are |
| // typically found in PEM blocks with "BEGIN PUBLIC KEY". |
| // |
| // Supported key types include RSA, DSA, and ECDSA. Unknown key |
| // types result in an error. |
| // |
| // On success, pub will be of type *rsa.PublicKey, *dsa.PublicKey, |
| // or *ecdsa.PublicKey. |
| func ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err error) { |
| var pki publicKeyInfo |
| if rest, err := asn1.Unmarshal(derBytes, &pki); err != nil { |
| return nil, err |
| } else if len(rest) != 0 { |
| return nil, errors.New("x509: trailing data after ASN.1 of public-key") |
| } |
| algo := getPublicKeyAlgorithmFromOID(pki.Algorithm.Algorithm) |
| if algo == UnknownPublicKeyAlgorithm { |
| return nil, errors.New("x509: unknown public key algorithm") |
| } |
| return parsePublicKey(algo, &pki) |
| } |
| |
| func marshalPublicKey(pub interface{}) (publicKeyBytes []byte, publicKeyAlgorithm pkix.AlgorithmIdentifier, err error) { |
| switch pub := pub.(type) { |
| case *rsa.PublicKey: |
| publicKeyBytes, err = asn1.Marshal(pkcs1PublicKey{ |
| N: pub.N, |
| E: pub.E, |
| }) |
| if err != nil { |
| return nil, pkix.AlgorithmIdentifier{}, err |
| } |
| publicKeyAlgorithm.Algorithm = oidPublicKeyRSA |
| // This is a NULL parameters value which is required by |
| // https://tools.ietf.org/html/rfc3279#section-2.3.1. |
| publicKeyAlgorithm.Parameters = asn1.NullRawValue |
| case *ecdsa.PublicKey: |
| publicKeyBytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y) |
| oid, ok := oidFromNamedCurve(pub.Curve) |
| if !ok { |
| return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: unsupported elliptic curve") |
| } |
| publicKeyAlgorithm.Algorithm = oidPublicKeyECDSA |
| var paramBytes []byte |
| paramBytes, err = asn1.Marshal(oid) |
| if err != nil { |
| return |
| } |
| publicKeyAlgorithm.Parameters.FullBytes = paramBytes |
| default: |
| return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: only RSA and ECDSA public keys supported") |
| } |
| |
| return publicKeyBytes, publicKeyAlgorithm, nil |
| } |
| |
| // MarshalPKIXPublicKey serialises a public key to DER-encoded PKIX format. |
| func MarshalPKIXPublicKey(pub interface{}) ([]byte, error) { |
| var publicKeyBytes []byte |
| var publicKeyAlgorithm pkix.AlgorithmIdentifier |
| var err error |
| |
| if publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(pub); err != nil { |
| return nil, err |
| } |
| |
| pkix := pkixPublicKey{ |
| Algo: publicKeyAlgorithm, |
| BitString: asn1.BitString{ |
| Bytes: publicKeyBytes, |
| BitLength: 8 * len(publicKeyBytes), |
| }, |
| } |
| |
| ret, _ := asn1.Marshal(pkix) |
| return ret, nil |
| } |
| |
| // These structures reflect the ASN.1 structure of X.509 certificates.: |
| |
| type certificate struct { |
| Raw asn1.RawContent |
| TBSCertificate tbsCertificate |
| SignatureAlgorithm pkix.AlgorithmIdentifier |
| SignatureValue asn1.BitString |
| } |
| |
| type tbsCertificate struct { |
| Raw asn1.RawContent |
| Version int `asn1:"optional,explicit,default:0,tag:0"` |
| SerialNumber *big.Int |
| SignatureAlgorithm pkix.AlgorithmIdentifier |
| Issuer asn1.RawValue |
| Validity validity |
| Subject asn1.RawValue |
| PublicKey publicKeyInfo |
| UniqueId asn1.BitString `asn1:"optional,tag:1"` |
| SubjectUniqueId asn1.BitString `asn1:"optional,tag:2"` |
| Extensions []pkix.Extension `asn1:"optional,explicit,tag:3"` |
| } |
| |
| type dsaAlgorithmParameters struct { |
| P, Q, G *big.Int |
| } |
| |
| type dsaSignature struct { |
| R, S *big.Int |
| } |
| |
| type ecdsaSignature dsaSignature |
| |
| type validity struct { |
| NotBefore, NotAfter time.Time |
| } |
| |
| type publicKeyInfo struct { |
| Raw asn1.RawContent |
| Algorithm pkix.AlgorithmIdentifier |
| PublicKey asn1.BitString |
| } |
| |
| // RFC 5280, 4.2.1.1 |
| type authKeyId struct { |
| Id []byte `asn1:"optional,tag:0"` |
| } |
| |
| type SignatureAlgorithm int |
| |
| const ( |
| UnknownSignatureAlgorithm SignatureAlgorithm = iota |
| MD2WithRSA |
| MD5WithRSA |
| SHA1WithRSA |
| SHA256WithRSA |
| SHA384WithRSA |
| SHA512WithRSA |
| DSAWithSHA1 |
| DSAWithSHA256 |
| ECDSAWithSHA1 |
| ECDSAWithSHA256 |
| ECDSAWithSHA384 |
| ECDSAWithSHA512 |
| SHA256WithRSAPSS |
| SHA384WithRSAPSS |
| SHA512WithRSAPSS |
| ) |
| |
| func (algo SignatureAlgorithm) isRSAPSS() bool { |
| switch algo { |
| case SHA256WithRSAPSS, SHA384WithRSAPSS, SHA512WithRSAPSS: |
| return true |
| default: |
| return false |
| } |
| } |
| |
| func (algo SignatureAlgorithm) String() string { |
| for _, details := range signatureAlgorithmDetails { |
| if details.algo == algo { |
| return details.name |
| } |
| } |
| return strconv.Itoa(int(algo)) |
| } |
| |
| type PublicKeyAlgorithm int |
| |
| const ( |
| UnknownPublicKeyAlgorithm PublicKeyAlgorithm = iota |
| RSA |
| DSA |
| ECDSA |
| ) |
| |
| var publicKeyAlgoName = [...]string{ |
| RSA: "RSA", |
| DSA: "DSA", |
| ECDSA: "ECDSA", |
| } |
| |
| func (algo PublicKeyAlgorithm) String() string { |
| if 0 < algo && int(algo) < len(publicKeyAlgoName) { |
| return publicKeyAlgoName[algo] |
| } |
| return strconv.Itoa(int(algo)) |
| } |
| |
| // OIDs for signature algorithms |
| // |
| // pkcs-1 OBJECT IDENTIFIER ::= { |
| // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 } |
| // |
| // |
| // RFC 3279 2.2.1 RSA Signature Algorithms |
| // |
| // md2WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 2 } |
| // |
| // md5WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 } |
| // |
| // sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 } |
| // |
| // dsaWithSha1 OBJECT IDENTIFIER ::= { |
| // iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 3 } |
| // |
| // RFC 3279 2.2.3 ECDSA Signature Algorithm |
| // |
| // ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { |
| // iso(1) member-body(2) us(840) ansi-x962(10045) |
| // signatures(4) ecdsa-with-SHA1(1)} |
| // |
| // |
| // RFC 4055 5 PKCS #1 Version 1.5 |
| // |
| // sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 } |
| // |
| // sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 } |
| // |
| // sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 } |
| // |
| // |
| // RFC 5758 3.1 DSA Signature Algorithms |
| // |
| // dsaWithSha256 OBJECT IDENTIFIER ::= { |
| // joint-iso-ccitt(2) country(16) us(840) organization(1) gov(101) |
| // csor(3) algorithms(4) id-dsa-with-sha2(3) 2} |
| // |
| // RFC 5758 3.2 ECDSA Signature Algorithm |
| // |
| // ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2) |
| // us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 } |
| // |
| // ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { iso(1) member-body(2) |
| // us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 3 } |
| // |
| // ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { iso(1) member-body(2) |
| // us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 4 } |
| |
| var ( |
| oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2} |
| oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4} |
| oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5} |
| oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11} |
| oidSignatureSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12} |
| oidSignatureSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13} |
| oidSignatureRSAPSS = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10} |
| oidSignatureDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3} |
| oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 2} |
| oidSignatureECDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1} |
| oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2} |
| oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3} |
| oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4} |
| |
| oidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1} |
| oidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2} |
| oidSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3} |
| |
| oidMGF1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 8} |
| |
| // oidISOSignatureSHA1WithRSA means the same as oidSignatureSHA1WithRSA |
| // but it's specified by ISO. Microsoft's makecert.exe has been known |
| // to produce certificates with this OID. |
| oidISOSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 29} |
| ) |
| |
| var signatureAlgorithmDetails = []struct { |
| algo SignatureAlgorithm |
| name string |
| oid asn1.ObjectIdentifier |
| pubKeyAlgo PublicKeyAlgorithm |
| hash crypto.Hash |
| }{ |
| {MD2WithRSA, "MD2-RSA", oidSignatureMD2WithRSA, RSA, crypto.Hash(0) /* no value for MD2 */}, |
| {MD5WithRSA, "MD5-RSA", oidSignatureMD5WithRSA, RSA, crypto.MD5}, |
| {SHA1WithRSA, "SHA1-RSA", oidSignatureSHA1WithRSA, RSA, crypto.SHA1}, |
| {SHA1WithRSA, "SHA1-RSA", oidISOSignatureSHA1WithRSA, RSA, crypto.SHA1}, |
| {SHA256WithRSA, "SHA256-RSA", oidSignatureSHA256WithRSA, RSA, crypto.SHA256}, |
| {SHA384WithRSA, "SHA384-RSA", oidSignatureSHA384WithRSA, RSA, crypto.SHA384}, |
| {SHA512WithRSA, "SHA512-RSA", oidSignatureSHA512WithRSA, RSA, crypto.SHA512}, |
| {SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, RSA, crypto.SHA256}, |
| {SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, RSA, crypto.SHA384}, |
| {SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, RSA, crypto.SHA512}, |
| {DSAWithSHA1, "DSA-SHA1", oidSignatureDSAWithSHA1, DSA, crypto.SHA1}, |
| {DSAWithSHA256, "DSA-SHA256", oidSignatureDSAWithSHA256, DSA, crypto.SHA256}, |
| {ECDSAWithSHA1, "ECDSA-SHA1", oidSignatureECDSAWithSHA1, ECDSA, crypto.SHA1}, |
| {ECDSAWithSHA256, "ECDSA-SHA256", oidSignatureECDSAWithSHA256, ECDSA, crypto.SHA256}, |
| {ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, ECDSA, crypto.SHA384}, |
| {ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, ECDSA, crypto.SHA512}, |
| } |
| |
| // pssParameters reflects the parameters in an AlgorithmIdentifier that |
| // specifies RSA PSS. See https://tools.ietf.org/html/rfc3447#appendix-A.2.3 |
| type pssParameters struct { |
| // The following three fields are not marked as |
| // optional because the default values specify SHA-1, |
| // which is no longer suitable for use in signatures. |
| Hash pkix.AlgorithmIdentifier `asn1:"explicit,tag:0"` |
| MGF pkix.AlgorithmIdentifier `asn1:"explicit,tag:1"` |
| SaltLength int `asn1:"explicit,tag:2"` |
| TrailerField int `asn1:"optional,explicit,tag:3,default:1"` |
| } |
| |
| // rsaPSSParameters returns an asn1.RawValue suitable for use as the Parameters |
| // in an AlgorithmIdentifier that specifies RSA PSS. |
| func rsaPSSParameters(hashFunc crypto.Hash) asn1.RawValue { |
| var hashOID asn1.ObjectIdentifier |
| |
| switch hashFunc { |
| case crypto.SHA256: |
| hashOID = oidSHA256 |
| case crypto.SHA384: |
| hashOID = oidSHA384 |
| case crypto.SHA512: |
| hashOID = oidSHA512 |
| } |
| |
| params := pssParameters{ |
| Hash: pkix.AlgorithmIdentifier{ |
| Algorithm: hashOID, |
| Parameters: asn1.NullRawValue, |
| }, |
| MGF: pkix.AlgorithmIdentifier{ |
| Algorithm: oidMGF1, |
| }, |
| SaltLength: hashFunc.Size(), |
| TrailerField: 1, |
| } |
| |
| mgf1Params := pkix.AlgorithmIdentifier{ |
| Algorithm: hashOID, |
| Parameters: asn1.NullRawValue, |
| } |
| |
| var err error |
| params.MGF.Parameters.FullBytes, err = asn1.Marshal(mgf1Params) |
| if err != nil { |
| panic(err) |
| } |
| |
| serialized, err := asn1.Marshal(params) |
| if err != nil { |
| panic(err) |
| } |
| |
| return asn1.RawValue{FullBytes: serialized} |
| } |
| |
| func getSignatureAlgorithmFromAI(ai pkix.AlgorithmIdentifier) SignatureAlgorithm { |
| if !ai.Algorithm.Equal(oidSignatureRSAPSS) { |
| for _, details := range signatureAlgorithmDetails { |
| if ai.Algorithm.Equal(details.oid) { |
| return details.algo |
| } |
| } |
| return UnknownSignatureAlgorithm |
| } |
| |
| // RSA PSS is special because it encodes important parameters |
| // in the Parameters. |
| |
| var params pssParameters |
| if _, err := asn1.Unmarshal(ai.Parameters.FullBytes, ¶ms); err != nil { |
| return UnknownSignatureAlgorithm |
| } |
| |
| var mgf1HashFunc pkix.AlgorithmIdentifier |
| if _, err := asn1.Unmarshal(params.MGF.Parameters.FullBytes, &mgf1HashFunc); err != nil { |
| return UnknownSignatureAlgorithm |
| } |
| |
| // PSS is greatly overburdened with options. This code forces |
| // them into three buckets by requiring that the MGF1 hash |
| // function always match the message hash function (as |
| // recommended in |
| // https://tools.ietf.org/html/rfc3447#section-8.1), that the |
| // salt length matches the hash length, and that the trailer |
| // field has the default value. |
| if !bytes.Equal(params.Hash.Parameters.FullBytes, asn1.NullBytes) || |
| !params.MGF.Algorithm.Equal(oidMGF1) || |
| !mgf1HashFunc.Algorithm.Equal(params.Hash.Algorithm) || |
| !bytes.Equal(mgf1HashFunc.Parameters.FullBytes, asn1.NullBytes) || |
| params.TrailerField != 1 { |
| return UnknownSignatureAlgorithm |
| } |
| |
| switch { |
| case params.Hash.Algorithm.Equal(oidSHA256) && params.SaltLength == 32: |
| return SHA256WithRSAPSS |
| case params.Hash.Algorithm.Equal(oidSHA384) && params.SaltLength == 48: |
| return SHA384WithRSAPSS |
| case params.Hash.Algorithm.Equal(oidSHA512) && params.SaltLength == 64: |
| return SHA512WithRSAPSS |
| } |
| |
| return UnknownSignatureAlgorithm |
| } |
| |
| // RFC 3279, 2.3 Public Key Algorithms |
| // |
| // pkcs-1 OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840) |
| // rsadsi(113549) pkcs(1) 1 } |
| // |
| // rsaEncryption OBJECT IDENTIFIER ::== { pkcs1-1 1 } |
| // |
| // id-dsa OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840) |
| // x9-57(10040) x9cm(4) 1 } |
| // |
| // RFC 5480, 2.1.1 Unrestricted Algorithm Identifier and Parameters |
| // |
| // id-ecPublicKey OBJECT IDENTIFIER ::= { |
| // iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 } |
| var ( |
| oidPublicKeyRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1} |
| oidPublicKeyDSA = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1} |
| oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1} |
| ) |
| |
| func getPublicKeyAlgorithmFromOID(oid asn1.ObjectIdentifier) PublicKeyAlgorithm { |
| switch { |
| case oid.Equal(oidPublicKeyRSA): |
| return RSA |
| case oid.Equal(oidPublicKeyDSA): |
| return DSA |
| case oid.Equal(oidPublicKeyECDSA): |
| return ECDSA |
| } |
| return UnknownPublicKeyAlgorithm |
| } |
| |
| // RFC 5480, 2.1.1.1. Named Curve |
| // |
| // secp224r1 OBJECT IDENTIFIER ::= { |
| // iso(1) identified-organization(3) certicom(132) curve(0) 33 } |
| // |
| // secp256r1 OBJECT IDENTIFIER ::= { |
| // iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) |
| // prime(1) 7 } |
| // |
| // secp384r1 OBJECT IDENTIFIER ::= { |
| // iso(1) identified-organization(3) certicom(132) curve(0) 34 } |
| // |
| // secp521r1 OBJECT IDENTIFIER ::= { |
| // iso(1) identified-organization(3) certicom(132) curve(0) 35 } |
| // |
| // NB: secp256r1 is equivalent to prime256v1 |
| var ( |
| oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33} |
| oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7} |
| oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34} |
| oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35} |
| ) |
| |
| func namedCurveFromOID(oid asn1.ObjectIdentifier) elliptic.Curve { |
| switch { |
| case oid.Equal(oidNamedCurveP224): |
| return elliptic.P224() |
| case oid.Equal(oidNamedCurveP256): |
| return elliptic.P256() |
| case oid.Equal(oidNamedCurveP384): |
| return elliptic.P384() |
| case oid.Equal(oidNamedCurveP521): |
| return elliptic.P521() |
| } |
| return nil |
| } |
| |
| func oidFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) { |
| switch curve { |
| case elliptic.P224(): |
| return oidNamedCurveP224, true |
| case elliptic.P256(): |
| return oidNamedCurveP256, true |
| case elliptic.P384(): |
| return oidNamedCurveP384, true |
| case elliptic.P521(): |
| return oidNamedCurveP521, true |
| } |
| |
| return nil, false |
| } |
| |
| // KeyUsage represents the set of actions that are valid for a given key. It's |
| // a bitmap of the KeyUsage* constants. |
| type KeyUsage int |
| |
| const ( |
| KeyUsageDigitalSignature KeyUsage = 1 << iota |
| KeyUsageContentCommitment |
| KeyUsageKeyEncipherment |
| KeyUsageDataEncipherment |
| KeyUsageKeyAgreement |
| KeyUsageCertSign |
| KeyUsageCRLSign |
| KeyUsageEncipherOnly |
| KeyUsageDecipherOnly |
| ) |
| |
| // RFC 5280, 4.2.1.12 Extended Key Usage |
| // |
| // anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 } |
| // |
| // id-kp OBJECT IDENTIFIER ::= { id-pkix 3 } |
| // |
| // id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 } |
| // id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 } |
| // id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 } |
| // id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 } |
| // id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 } |
| // id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 } |
| var ( |
| oidExtKeyUsageAny = asn1.ObjectIdentifier{2, 5, 29, 37, 0} |
| oidExtKeyUsageServerAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1} |
| oidExtKeyUsageClientAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 2} |
| oidExtKeyUsageCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 3} |
| oidExtKeyUsageEmailProtection = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 4} |
| oidExtKeyUsageIPSECEndSystem = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 5} |
| oidExtKeyUsageIPSECTunnel = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 6} |
| oidExtKeyUsageIPSECUser = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 7} |
| oidExtKeyUsageTimeStamping = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8} |
| oidExtKeyUsageOCSPSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9} |
| oidExtKeyUsageMicrosoftServerGatedCrypto = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 3} |
| oidExtKeyUsageNetscapeServerGatedCrypto = asn1.ObjectIdentifier{2, 16, 840, 1, 113730, 4, 1} |
| oidExtKeyUsageMicrosoftCommercialCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 2, 1, 22} |
| oidExtKeyUsageMicrosoftKernelCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 61, 1, 1} |
| ) |
| |
| // ExtKeyUsage represents an extended set of actions that are valid for a given key. |
| // Each of the ExtKeyUsage* constants define a unique action. |
| type ExtKeyUsage int |
| |
| const ( |
| ExtKeyUsageAny ExtKeyUsage = iota |
| ExtKeyUsageServerAuth |
| ExtKeyUsageClientAuth |
| ExtKeyUsageCodeSigning |
| ExtKeyUsageEmailProtection |
| ExtKeyUsageIPSECEndSystem |
| ExtKeyUsageIPSECTunnel |
| ExtKeyUsageIPSECUser |
| ExtKeyUsageTimeStamping |
| ExtKeyUsageOCSPSigning |
| ExtKeyUsageMicrosoftServerGatedCrypto |
| ExtKeyUsageNetscapeServerGatedCrypto |
| ExtKeyUsageMicrosoftCommercialCodeSigning |
| ExtKeyUsageMicrosoftKernelCodeSigning |
| ) |
| |
| // extKeyUsageOIDs contains the mapping between an ExtKeyUsage and its OID. |
| var extKeyUsageOIDs = []struct { |
| extKeyUsage ExtKeyUsage |
| oid asn1.ObjectIdentifier |
| }{ |
| {ExtKeyUsageAny, oidExtKeyUsageAny}, |
| {ExtKeyUsageServerAuth, oidExtKeyUsageServerAuth}, |
| {ExtKeyUsageClientAuth, oidExtKeyUsageClientAuth}, |
| {ExtKeyUsageCodeSigning, oidExtKeyUsageCodeSigning}, |
| {ExtKeyUsageEmailProtection, oidExtKeyUsageEmailProtection}, |
| {ExtKeyUsageIPSECEndSystem, oidExtKeyUsageIPSECEndSystem}, |
| {ExtKeyUsageIPSECTunnel, oidExtKeyUsageIPSECTunnel}, |
| {ExtKeyUsageIPSECUser, oidExtKeyUsageIPSECUser}, |
| {ExtKeyUsageTimeStamping, oidExtKeyUsageTimeStamping}, |
| {ExtKeyUsageOCSPSigning, oidExtKeyUsageOCSPSigning}, |
| {ExtKeyUsageMicrosoftServerGatedCrypto, oidExtKeyUsageMicrosoftServerGatedCrypto}, |
| {ExtKeyUsageNetscapeServerGatedCrypto, oidExtKeyUsageNetscapeServerGatedCrypto}, |
| {ExtKeyUsageMicrosoftCommercialCodeSigning, oidExtKeyUsageMicrosoftCommercialCodeSigning}, |
| {ExtKeyUsageMicrosoftKernelCodeSigning, oidExtKeyUsageMicrosoftKernelCodeSigning}, |
| } |
| |
| func extKeyUsageFromOID(oid asn1.ObjectIdentifier) (eku ExtKeyUsage, ok bool) { |
| for _, pair := range extKeyUsageOIDs { |
| if oid.Equal(pair.oid) { |
| return pair.extKeyUsage, true |
| } |
| } |
| return |
| } |
| |
| func oidFromExtKeyUsage(eku ExtKeyUsage) (oid asn1.ObjectIdentifier, ok bool) { |
| for _, pair := range extKeyUsageOIDs { |
| if eku == pair.extKeyUsage { |
| return pair.oid, true |
| } |
| } |
| return |
| } |
| |
| // A Certificate represents an X.509 certificate. |
| type Certificate struct { |
| Raw []byte // Complete ASN.1 DER content (certificate, signature algorithm and signature). |
| RawTBSCertificate []byte // Certificate part of raw ASN.1 DER content. |
| RawSubjectPublicKeyInfo []byte // DER encoded SubjectPublicKeyInfo. |
| RawSubject []byte // DER encoded Subject |
| RawIssuer []byte // DER encoded Issuer |
| |
| Signature []byte |
| SignatureAlgorithm SignatureAlgorithm |
| |
| PublicKeyAlgorithm PublicKeyAlgorithm |
| PublicKey interface{} |
| |
| Version int |
| SerialNumber *big.Int |
| Issuer pkix.Name |
| Subject pkix.Name |
| NotBefore, NotAfter time.Time // Validity bounds. |
| KeyUsage KeyUsage |
| |
| // Extensions contains raw X.509 extensions. When parsing certificates, |
| // this can be used to extract non-critical extensions that are not |
| // parsed by this package. When marshaling certificates, the Extensions |
| // field is ignored, see ExtraExtensions. |
| Extensions []pkix.Extension |
| |
| // ExtraExtensions contains extensions to be copied, raw, into any |
| // marshaled certificates. Values override any extensions that would |
| // otherwise be produced based on the other fields. The ExtraExtensions |
| // field is not populated when parsing certificates, see Extensions. |
| ExtraExtensions []pkix.Extension |
| |
| // UnhandledCriticalExtensions contains a list of extension IDs that |
| // were not (fully) processed when parsing. Verify will fail if this |
| // slice is non-empty, unless verification is delegated to an OS |
| // library which understands all the critical extensions. |
| // |
| // Users can access these extensions using Extensions and can remove |
| // elements from this slice if they believe that they have been |
| // handled. |
| UnhandledCriticalExtensions []asn1.ObjectIdentifier |
| |
| ExtKeyUsage []ExtKeyUsage // Sequence of extended key usages. |
| UnknownExtKeyUsage []asn1.ObjectIdentifier // Encountered extended key usages unknown to this package. |
| |
| // BasicConstraintsValid indicates whether IsCA, MaxPathLen, |
| // and MaxPathLenZero are valid. |
| BasicConstraintsValid bool |
| IsCA bool |
| |
| // MaxPathLen and MaxPathLenZero indicate the presence and |
| // value of the BasicConstraints' "pathLenConstraint". |
| // |
| // When parsing a certificate, a positive non-zero MaxPathLen |
| // means that the field was specified, -1 means it was unset, |
| // and MaxPathLenZero being true mean that the field was |
| // explicitly set to zero. The case of MaxPathLen==0 with MaxPathLenZero==false |
| // should be treated equivalent to -1 (unset). |
| // |
| // When generating a certificate, an unset pathLenConstraint |
| // can be requested with either MaxPathLen == -1 or using the |
| // zero value for both MaxPathLen and MaxPathLenZero. |
| MaxPathLen int |
| // MaxPathLenZero indicates that BasicConstraintsValid==true |
| // and MaxPathLen==0 should be interpreted as an actual |
| // maximum path length of zero. Otherwise, that combination is |
| // interpreted as MaxPathLen not being set. |
| MaxPathLenZero bool |
| |
| SubjectKeyId []byte |
| AuthorityKeyId []byte |
| |
| // RFC 5280, 4.2.2.1 (Authority Information Access) |
| OCSPServer []string |
| IssuingCertificateURL []string |
| |
| // Subject Alternate Name values. (Note that these values may not be valid |
| // if invalid values were contained within a parsed certificate. For |
| // example, an element of DNSNames may not be a valid DNS domain name.) |
| DNSNames []string |
| EmailAddresses []string |
| IPAddresses []net.IP |
| URIs []*url.URL |
| |
| // Name constraints |
| PermittedDNSDomainsCritical bool // if true then the name constraints are marked critical. |
| PermittedDNSDomains []string |
| ExcludedDNSDomains []string |
| PermittedIPRanges []*net.IPNet |
| ExcludedIPRanges []*net.IPNet |
| PermittedEmailAddresses []string |
| ExcludedEmailAddresses []string |
| PermittedURIDomains []string |
| ExcludedURIDomains []string |
| |
| // CRL Distribution Points |
| CRLDistributionPoints []string |
| |
| PolicyIdentifiers []asn1.ObjectIdentifier |
| } |
| |
| // ErrUnsupportedAlgorithm results from attempting to perform an operation that |
| // involves algorithms that are not currently implemented. |
| var ErrUnsupportedAlgorithm = errors.New("x509: cannot verify signature: algorithm unimplemented") |
| |
| // An InsecureAlgorithmError |
| type InsecureAlgorithmError SignatureAlgorithm |
| |
| func (e InsecureAlgorithmError) Error() string { |
| return fmt.Sprintf("x509: cannot verify signature: insecure algorithm %v", SignatureAlgorithm(e)) |
| } |
| |
| // ConstraintViolationError results when a requested usage is not permitted by |
| // a certificate. For example: checking a signature when the public key isn't a |
| // certificate signing key. |
| type ConstraintViolationError struct{} |
| |
| func (ConstraintViolationError) Error() string { |
| return "x509: invalid signature: parent certificate cannot sign this kind of certificate" |
| } |
| |
| func (c *Certificate) Equal(other *Certificate) bool { |
| return bytes.Equal(c.Raw, other.Raw) |
| } |
| |
| func (c *Certificate) hasSANExtension() bool { |
| return oidInExtensions(oidExtensionSubjectAltName, c.Extensions) |
| } |
| |
| // Entrust have a broken root certificate (CN=Entrust.net Certification |
| // Authority (2048)) which isn't marked as a CA certificate and is thus invalid |
| // according to PKIX. |
| // We recognise this certificate by its SubjectPublicKeyInfo and exempt it |
| // from the Basic Constraints requirement. |
| // See http://www.entrust.net/knowledge-base/technote.cfm?tn=7869 |
| // |
| // TODO(agl): remove this hack once their reissued root is sufficiently |
| // widespread. |
| var entrustBrokenSPKI = []byte{ |
| 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, |
| 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, |
| 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, |
| 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, |
| 0x00, 0x97, 0xa3, 0x2d, 0x3c, 0x9e, 0xde, 0x05, |
| 0xda, 0x13, 0xc2, 0x11, 0x8d, 0x9d, 0x8e, 0xe3, |
| 0x7f, 0xc7, 0x4b, 0x7e, 0x5a, 0x9f, 0xb3, 0xff, |
| 0x62, 0xab, 0x73, 0xc8, 0x28, 0x6b, 0xba, 0x10, |
| 0x64, 0x82, 0x87, 0x13, 0xcd, 0x57, 0x18, 0xff, |
| 0x28, 0xce, 0xc0, 0xe6, 0x0e, 0x06, 0x91, 0x50, |
| 0x29, 0x83, 0xd1, 0xf2, 0xc3, 0x2a, 0xdb, 0xd8, |
| 0xdb, 0x4e, 0x04, 0xcc, 0x00, 0xeb, 0x8b, 0xb6, |
| 0x96, 0xdc, 0xbc, 0xaa, 0xfa, 0x52, 0x77, 0x04, |
| 0xc1, 0xdb, 0x19, 0xe4, 0xae, 0x9c, 0xfd, 0x3c, |
| 0x8b, 0x03, 0xef, 0x4d, 0xbc, 0x1a, 0x03, 0x65, |
| 0xf9, 0xc1, 0xb1, 0x3f, 0x72, 0x86, 0xf2, 0x38, |
| 0xaa, 0x19, 0xae, 0x10, 0x88, 0x78, 0x28, 0xda, |
| 0x75, 0xc3, 0x3d, 0x02, 0x82, 0x02, 0x9c, 0xb9, |
| 0xc1, 0x65, 0x77, 0x76, 0x24, 0x4c, 0x98, 0xf7, |
| 0x6d, 0x31, 0x38, 0xfb, 0xdb, 0xfe, 0xdb, 0x37, |
| 0x02, 0x76, 0xa1, 0x18, 0x97, 0xa6, 0xcc, 0xde, |
| 0x20, 0x09, 0x49, 0x36, 0x24, 0x69, 0x42, 0xf6, |
| 0xe4, 0x37, 0x62, 0xf1, 0x59, 0x6d, 0xa9, 0x3c, |
| 0xed, 0x34, 0x9c, 0xa3, 0x8e, 0xdb, 0xdc, 0x3a, |
| 0xd7, 0xf7, 0x0a, 0x6f, 0xef, 0x2e, 0xd8, 0xd5, |
| 0x93, 0x5a, 0x7a, 0xed, 0x08, 0x49, 0x68, 0xe2, |
| 0x41, 0xe3, 0x5a, 0x90, 0xc1, 0x86, 0x55, 0xfc, |
| 0x51, 0x43, 0x9d, 0xe0, 0xb2, 0xc4, 0x67, 0xb4, |
| 0xcb, 0x32, 0x31, 0x25, 0xf0, 0x54, 0x9f, 0x4b, |
| 0xd1, 0x6f, 0xdb, 0xd4, 0xdd, 0xfc, 0xaf, 0x5e, |
| 0x6c, 0x78, 0x90, 0x95, 0xde, 0xca, 0x3a, 0x48, |
| 0xb9, 0x79, 0x3c, 0x9b, 0x19, 0xd6, 0x75, 0x05, |
| 0xa0, 0xf9, 0x88, 0xd7, 0xc1, 0xe8, 0xa5, 0x09, |
| 0xe4, 0x1a, 0x15, 0xdc, 0x87, 0x23, 0xaa, 0xb2, |
| 0x75, 0x8c, 0x63, 0x25, 0x87, 0xd8, 0xf8, 0x3d, |
| 0xa6, 0xc2, 0xcc, 0x66, 0xff, 0xa5, 0x66, 0x68, |
| 0x55, 0x02, 0x03, 0x01, 0x00, 0x01, |
| } |
| |
| // CheckSignatureFrom verifies that the signature on c is a valid signature |
| // from parent. |
| func (c *Certificate) CheckSignatureFrom(parent *Certificate) error { |
| // RFC 5280, 4.2.1.9: |
| // "If the basic constraints extension is not present in a version 3 |
| // certificate, or the extension is present but the cA boolean is not |
| // asserted, then the certified public key MUST NOT be used to verify |
| // certificate signatures." |
| // (except for Entrust, see comment above entrustBrokenSPKI) |
| if (parent.Version == 3 && !parent.BasicConstraintsValid || |
| parent.BasicConstraintsValid && !parent.IsCA) && |
| !bytes.Equal(c.RawSubjectPublicKeyInfo, entrustBrokenSPKI) { |
| return ConstraintViolationError{} |
| } |
| |
| if parent.KeyUsage != 0 && parent.KeyUsage&KeyUsageCertSign == 0 { |
| return ConstraintViolationError{} |
| } |
| |
| if parent.PublicKeyAlgorithm == UnknownPublicKeyAlgorithm { |
| return ErrUnsupportedAlgorithm |
| } |
| |
| // TODO(agl): don't ignore the path length constraint. |
| |
| return parent.CheckSignature(c.SignatureAlgorithm, c.RawTBSCertificate, c.Signature) |
| } |
| |
| // CheckSignature verifies that signature is a valid signature over signed from |
| // c's public key. |
| func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature []byte) error { |
| return checkSignature(algo, signed, signature, c.PublicKey) |
| } |
| |
| func (c *Certificate) hasNameConstraints() bool { |
| for _, e := range c.Extensions { |
| if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 && e.Id[3] == 30 { |
| return true |
| } |
| } |
| |
| return false |
| } |
| |
| func (c *Certificate) getSANExtension() ([]byte, bool) { |
| for _, e := range c.Extensions { |
| if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 && e.Id[3] == 17 { |
| return e.Value, true |
| } |
| } |
| |
| return nil, false |
| } |
| |
| func signaturePublicKeyAlgoMismatchError(expectedPubKeyAlgo PublicKeyAlgorithm, pubKey interface{}) error { |
| return fmt.Errorf("x509: signature algorithm specifies an %s public key, but have public key of type %T", expectedPubKeyAlgo.String(), pubKey) |
| } |
| |
| // CheckSignature verifies that signature is a valid signature over signed from |
| // a crypto.PublicKey. |
| func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey crypto.PublicKey) (err error) { |
| var hashType crypto.Hash |
| var pubKeyAlgo PublicKeyAlgorithm |
| |
| for _, details := range signatureAlgorithmDetails { |
| if details.algo == algo { |
| hashType = details.hash |
| pubKeyAlgo = details.pubKeyAlgo |
| } |
| } |
| |
| switch hashType { |
| case crypto.Hash(0): |
| return ErrUnsupportedAlgorithm |
| case crypto.MD5: |
| return InsecureAlgorithmError(algo) |
| } |
| |
| if !hashType.Available() { |
| return ErrUnsupportedAlgorithm |
| } |
| h := hashType.New() |
| |
| h.Write(signed) |
| digest := h.Sum(nil) |
| |
| switch pub := publicKey.(type) { |
| case *rsa.PublicKey: |
| if pubKeyAlgo != RSA { |
| return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub) |
| } |
| if algo.isRSAPSS() { |
| return rsa.VerifyPSS(pub, hashType, digest, signature, &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash}) |
| } else { |
| return rsa.VerifyPKCS1v15(pub, hashType, digest, signature) |
| } |
| case *dsa.PublicKey: |
| if pubKeyAlgo != DSA { |
| return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub) |
| } |
| dsaSig := new(dsaSignature) |
| if rest, err := asn1.Unmarshal(signature, dsaSig); err != nil { |
| return err |
| } else if len(rest) != 0 { |
| return errors.New("x509: trailing data after DSA signature") |
| } |
| if dsaSig.R.Sign() <= 0 || dsaSig.S.Sign() <= 0 { |
| return errors.New("x509: DSA signature contained zero or negative values") |
| } |
| if !dsa.Verify(pub, digest, dsaSig.R, dsaSig.S) { |
| return errors.New("x509: DSA verification failure") |
| } |
| return |
| case *ecdsa.PublicKey: |
| if pubKeyAlgo != ECDSA { |
| return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub) |
| } |
| ecdsaSig := new(ecdsaSignature) |
| if rest, err := asn1.Unmarshal(signature, ecdsaSig); err != nil { |
| return err |
| } else if len(rest) != 0 { |
| return errors.New("x509: trailing data after ECDSA signature") |
| } |
| if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 { |
| return errors.New("x509: ECDSA signature contained zero or negative values") |
| } |
| if !ecdsa.Verify(pub, digest, ecdsaSig.R, ecdsaSig.S) { |
| return errors.New("x509: ECDSA verification failure") |
| } |
| return |
| } |
| return ErrUnsupportedAlgorithm |
| } |
| |
| // CheckCRLSignature checks that the signature in crl is from c. |
| func (c *Certificate) CheckCRLSignature(crl *pkix.CertificateList) error { |
| algo := getSignatureAlgorithmFromAI(crl.SignatureAlgorithm) |
| return c.CheckSignature(algo, crl.TBSCertList.Raw, crl.SignatureValue.RightAlign()) |
| } |
| |
| type UnhandledCriticalExtension struct{} |
| |
| func (h UnhandledCriticalExtension) Error() string { |
| return "x509: unhandled critical extension" |
| } |
| |
| type basicConstraints struct { |
| IsCA bool `asn1:"optional"` |
| MaxPathLen int `asn1:"optional,default:-1"` |
| } |
| |
| // RFC 5280 4.2.1.4 |
| type policyInformation struct { |
| Policy asn1.ObjectIdentifier |
| // policyQualifiers omitted |
| } |
| |
| const ( |
| nameTypeEmail = 1 |
| nameTypeDNS = 2 |
| nameTypeURI = 6 |
| nameTypeIP = 7 |
| ) |
| |
| // RFC 5280, 4.2.2.1 |
| type authorityInfoAccess struct { |
| Method asn1.ObjectIdentifier |
| Location asn1.RawValue |
| } |
| |
| // RFC 5280, 4.2.1.14 |
| type distributionPoint struct { |
| DistributionPoint distributionPointName `asn1:"optional,tag:0"` |
| Reason asn1.BitString `asn1:"optional,tag:1"` |
| CRLIssuer asn1.RawValue `asn1:"optional,tag:2"` |
| } |
| |
| type distributionPointName struct { |
| FullName []asn1.RawValue `asn1:"optional,tag:0"` |
| RelativeName pkix.RDNSequence `asn1:"optional,tag:1"` |
| } |
| |
| func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{}, error) { |
| asn1Data := keyData.PublicKey.RightAlign() |
| switch algo { |
| case RSA: |
| // RSA public keys must have a NULL in the parameters |
| // (https://tools.ietf.org/html/rfc3279#section-2.3.1). |
| if !bytes.Equal(keyData.Algorithm.Parameters.FullBytes, asn1.NullBytes) { |
| return nil, errors.New("x509: RSA key missing NULL parameters") |
| } |
| |
| p := new(pkcs1PublicKey) |
| rest, err := asn1.Unmarshal(asn1Data, p) |
| if err != nil { |
| return nil, err |
| } |
| if len(rest) != 0 { |
| return nil, errors.New("x509: trailing data after RSA public key") |
| } |
| |
| if p.N.Sign() <= 0 { |
| return nil, errors.New("x509: RSA modulus is not a positive number") |
| } |
| if p.E <= 0 { |
| return nil, errors.New("x509: RSA public exponent is not a positive number") |
| } |
| |
| pub := &rsa.PublicKey{ |
| E: p.E, |
| N: p.N, |
| } |
| return pub, nil |
| case DSA: |
| var p *big.Int |
| rest, err := asn1.Unmarshal(asn1Data, &p) |
| if err != nil { |
| return nil, err |
| } |
| if len(rest) != 0 { |
| return nil, errors.New("x509: trailing data after DSA public key") |
| } |
| paramsData := keyData.Algorithm.Parameters.FullBytes |
| params := new(dsaAlgorithmParameters) |
| rest, err = asn1.Unmarshal(paramsData, params) |
| if err != nil { |
| return nil, err |
| } |
| if len(rest) != 0 { |
| return nil, errors.New("x509: trailing data after DSA parameters") |
| } |
| if p.Sign() <= 0 || params.P.Sign() <= 0 || params.Q.Sign() <= 0 || params.G.Sign() <= 0 { |
| return nil, errors.New("x509: zero or negative DSA parameter") |
| } |
| pub := &dsa.PublicKey{ |
| Parameters: dsa.Parameters{ |
| P: params.P, |
| Q: params.Q, |
| G: params.G, |
| }, |
| Y: p, |
| } |
| return pub, nil |
| case ECDSA: |
| paramsData := keyData.Algorithm.Parameters.FullBytes |
| namedCurveOID := new(asn1.ObjectIdentifier) |
| rest, err := asn1.Unmarshal(paramsData, namedCurveOID) |
| if err != nil { |
| return nil, err |
| } |
| if len(rest) != 0 { |
| return nil, errors.New("x509: trailing data after ECDSA parameters") |
| } |
| namedCurve := namedCurveFromOID(*namedCurveOID) |
| if namedCurve == nil { |
| return nil, errors.New("x509: unsupported elliptic curve") |
| } |
| x, y := elliptic.Unmarshal(namedCurve, asn1Data) |
| if x == nil { |
| return nil, errors.New("x509: failed to unmarshal elliptic curve point") |
| } |
| pub := &ecdsa.PublicKey{ |
| Curve: namedCurve, |
| X: x, |
| Y: y, |
| } |
| return pub, nil |
| default: |
| return nil, nil |
| } |
| } |
| |
| func forEachSAN(extension []byte, callback func(tag int, data []byte) error) error { |
| // RFC 5280, 4.2.1.6 |
| |
| // SubjectAltName ::= GeneralNames |
| // |
| // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName |
| // |
| // GeneralName ::= CHOICE { |
| // otherName [0] OtherName, |
| // rfc822Name [1] IA5String, |
| // dNSName [2] IA5String, |
| // x400Address [3] ORAddress, |
| // directoryName [4] Name, |
| // ediPartyName [5] EDIPartyName, |
| // uniformResourceIdentifier [6] IA5String, |
| // iPAddress [7] OCTET STRING, |
| // registeredID [8] OBJECT IDENTIFIER } |
| var seq asn1.RawValue |
| rest, err := asn1.Unmarshal(extension, &seq) |
| if err != nil { |
| return err |
| } else if len(rest) != 0 { |
| return errors.New("x509: trailing data after X.509 extension") |
| } |
| if !seq.IsCompound || seq.Tag != 16 || seq.Class != 0 { |
| return asn1.StructuralError{Msg: "bad SAN sequence"} |
| } |
| |
| rest = seq.Bytes |
| for len(rest) > 0 { |
| var v asn1.RawValue |
| rest, err = asn1.Unmarshal(rest, &v) |
| if err != nil { |
| return err |
| } |
| |
| if err := callback(v.Tag, v.Bytes); err != nil { |
| return err |
| } |
| } |
| |
| return nil |
| } |
| |
| func parseSANExtension(value []byte) (dnsNames, emailAddresses []string, ipAddresses []net.IP, uris []*url.URL, err error) { |
| err = forEachSAN(value, func(tag int, data []byte) error { |
| switch tag { |
| case nameTypeEmail: |
| emailAddresses = append(emailAddresses, string(data)) |
| case nameTypeDNS: |
| dnsNames = append(dnsNames, string(data)) |
| case nameTypeURI: |
| uri, err := url.Parse(string(data)) |
| if err != nil { |
| return fmt.Errorf("x509: cannot parse URI %q: %s", string(data), err) |
| } |
| if len(uri.Host) > 0 { |
| if _, ok := domainToReverseLabels(uri.Host); !ok { |
| return fmt.Errorf("x509: cannot parse URI %q: invalid domain", string(data)) |
| } |
| } |
| uris = append(uris, uri) |
| case nameTypeIP: |
| switch len(data) { |
| case net.IPv4len, net.IPv6len: |
| ipAddresses = append(ipAddresses, data) |
| default: |
| return errors.New("x509: cannot parse IP address of length " + strconv.Itoa(len(data))) |
| } |
| } |
| |
| return nil |
| }) |
| |
| return |
| } |
| |
| // isValidIPMask returns true iff mask consists of zero or more 1 bits, followed by zero bits. |
| func isValidIPMask(mask []byte) bool { |
| seenZero := false |
| |
| for _, b := range mask { |
| if seenZero { |
| if b != 0 { |
| return false |
| } |
| |
| continue |
| } |
| |
| switch b { |
| case 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe: |
| seenZero = true |
| case 0xff: |
| default: |
| return false |
| } |
| } |
| |
| return true |
| } |
| |
| func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandled bool, err error) { |
| // RFC 5280, 4.2.1.10 |
| |
| // NameConstraints ::= SEQUENCE { |
| // permittedSubtrees [0] GeneralSubtrees OPTIONAL, |
| // excludedSubtrees [1] GeneralSubtrees OPTIONAL } |
| // |
| // GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree |
| // |
| // GeneralSubtree ::= SEQUENCE { |
| // base GeneralName, |
| // minimum [0] BaseDistance DEFAULT 0, |
| // maximum [1] BaseDistance OPTIONAL } |
| // |
| // BaseDistance ::= INTEGER (0..MAX) |
| |
| outer := cryptobyte.String(e.Value) |
| var toplevel, permitted, excluded cryptobyte.String |
| var havePermitted, haveExcluded bool |
| if !outer.ReadASN1(&toplevel, cryptobyte_asn1.SEQUENCE) || |
| !outer.Empty() || |
| !toplevel.ReadOptionalASN1(&permitted, &havePermitted, cryptobyte_asn1.Tag(0).ContextSpecific().Constructed()) || |
| !toplevel.ReadOptionalASN1(&excluded, &haveExcluded, cryptobyte_asn1.Tag(1).ContextSpecific().Constructed()) || |
| !toplevel.Empty() { |
| return false, errors.New("x509: invalid NameConstraints extension") |
| } |
| |
| if !havePermitted && !haveExcluded || len(permitted) == 0 && len(excluded) == 0 { |
| // https://tools.ietf.org/html/rfc5280#section-4.2.1.10: |
| // “either the permittedSubtrees field |
| // or the excludedSubtrees MUST be |
| // present” |
| return false, errors.New("x509: empty name constraints extension") |
| } |
| |
| getValues := func(subtrees cryptobyte.String) (dnsNames []string, ips []*net.IPNet, emails, uriDomains []string, err error) { |
| for !subtrees.Empty() { |
| var seq, value cryptobyte.String |
| var tag cryptobyte_asn1.Tag |
| if !subtrees.ReadASN1(&seq, cryptobyte_asn1.SEQUENCE) || |
| !seq.ReadAnyASN1(&value, &tag) { |
| return nil, nil, nil, nil, fmt.Errorf("x509: invalid NameConstraints extension") |
| } |
| |
| var ( |
| dnsTag = cryptobyte_asn1.Tag(2).ContextSpecific() |
| emailTag = cryptobyte_asn1.Tag(1).ContextSpecific() |
| ipTag = cryptobyte_asn1.Tag(7).ContextSpecific() |
| uriTag = cryptobyte_asn1.Tag(6).ContextSpecific() |
| ) |
| |
| switch tag { |
| case dnsTag: |
| domain := string(value) |
| if err := isIA5String(domain); err != nil { |
| return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error()) |
| } |
| |
| trimmedDomain := domain |
| if len(trimmedDomain) > 0 && trimmedDomain[0] == '.' { |
| // constraints can have a leading |
| // period to exclude the domain |
| // itself, but that's not valid in a |
| // normal domain name. |
| trimmedDomain = trimmedDomain[1:] |
| } |
| if _, ok := domainToReverseLabels(trimmedDomain); !ok { |
| return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse dnsName constraint %q", domain) |
| } |
| dnsNames = append(dnsNames, domain) |
| |
| case ipTag: |
| l := len(value) |
| var ip, mask []byte |
| |
| switch l { |
| case 8: |
| ip = value[:4] |
| mask = value[4:] |
| |
| case 32: |
| ip = value[:16] |
| mask = value[16:] |
| |
| default: |
| return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained value of length %d", l) |
| } |
| |
| if !isValidIPMask(mask) { |
| return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained invalid mask %x", mask) |
| } |
| |
| ips = append(ips, &net.IPNet{IP: net.IP(ip), Mask: net.IPMask(mask)}) |
| |
| case emailTag: |
| constraint := string(value) |
| if err := isIA5String(constraint); err != nil { |
| return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error()) |
| } |
| |
| // If the constraint contains an @ then |
| // it specifies an exact mailbox name. |
| if strings.Contains(constraint, "@") { |
| if _, ok := parseRFC2821Mailbox(constraint); !ok { |
| return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint) |
| } |
| } else { |
| // Otherwise it's a domain name. |
| domain := constraint |
| if len(domain) > 0 && domain[0] == '.' { |
| domain = domain[1:] |
| } |
| if _, ok := domainToReverseLabels(domain); !ok { |
| return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint) |
| } |
| } |
| emails = append(emails, constraint) |
| |
| case uriTag: |
| domain := string(value) |
| if err := isIA5String(domain); err != nil { |
| return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error()) |
| } |
| |
| if net.ParseIP(domain) != nil { |
| return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q: cannot be IP address", domain) |
| } |
| |
| trimmedDomain := domain |
| if len(trimmedDomain) > 0 && trimmedDomain[0] == '.' { |
| // constraints can have a leading |
| // period to exclude the domain itself, |
| // but that's not valid in a normal |
| // domain name. |
| trimmedDomain = trimmedDomain[1:] |
| } |
| if _, ok := domainToReverseLabels(trimmedDomain); !ok { |
| return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q", domain) |
| } |
| uriDomains = append(uriDomains, domain) |
| |
| default: |
| unhandled = true |
| } |
| } |
| |
| return dnsNames, ips, emails, uriDomains, nil |
| } |
| |
| if out.PermittedDNSDomains, out.PermittedIPRanges, out.PermittedEmailAddresses, out.PermittedURIDomains, err = getValues(permitted); err != nil { |
| return false, err |
| } |
| if out.ExcludedDNSDomains, out.ExcludedIPRanges, out.ExcludedEmailAddresses, out.ExcludedURIDomains, err = getValues(excluded); err != nil { |
| return false, err |
| } |
| out.PermittedDNSDomainsCritical = e.Critical |
| |
| return unhandled, nil |
| } |
| |
| func parseCertificate(in *certificate) (*Certificate, error) { |
| out := new(Certificate) |
| out.Raw = in.Raw |
| out.RawTBSCertificate = in.TBSCertificate.Raw |
| out.RawSubjectPublicKeyInfo = in.TBSCertificate.PublicKey.Raw |
| out.RawSubject = in.TBSCertificate.Subject.FullBytes |
| out.RawIssuer = in.TBSCertificate.Issuer.FullBytes |
| |
| out.Signature = in.SignatureValue.RightAlign() |
| out.SignatureAlgorithm = |
| getSignatureAlgorithmFromAI(in.TBSCertificate.SignatureAlgorithm) |
| |
| out.PublicKeyAlgorithm = |
| getPublicKeyAlgorithmFromOID(in.TBSCertificate.PublicKey.Algorithm.Algorithm) |
| var err error |
| out.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, &in.TBSCertificate.PublicKey) |
| if err != nil { |
| return nil, err |
| } |
| |
| out.Version = in.TBSCertificate.Version + 1 |
| out.SerialNumber = in.TBSCertificate.SerialNumber |
| |
| var issuer, subject pkix.RDNSequence |
| if rest, err := asn1.Unmarshal(in.TBSCertificate.Subject.FullBytes, &subject); err != nil { |
| return nil, err |
| } else if len(rest) != 0 { |
| return nil, errors.New("x509: trailing data after X.509 subject") |
| } |
| if rest, err := asn1.Unmarshal(in.TBSCertificate.Issuer.FullBytes, &issuer); err != nil { |
| return nil, err |
| } else if len(rest) != 0 { |
| return nil, errors.New("x509: trailing data after X.509 subject") |
| } |
| |
| out.Issuer.FillFromRDNSequence(&issuer) |
| out.Subject.FillFromRDNSequence(&subject) |
| |
| out.NotBefore = in.TBSCertificate.Validity.NotBefore |
| out.NotAfter = in.TBSCertificate.Validity.NotAfter |
| |
| for _, e := range in.TBSCertificate.Extensions { |
| out.Extensions = append(out.Extensions, e) |
| unhandled := false |
| |
| if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 { |
| switch e.Id[3] { |
| case 15: |
| // RFC 5280, 4.2.1.3 |
| var usageBits asn1.BitString |
| if rest, err := asn1.Unmarshal(e.Value, &usageBits); err != nil { |
| return nil, err |
| } else if len(rest) != 0 { |
| return nil, errors.New("x509: trailing data after X.509 KeyUsage") |
| } |
| |
| var usage int |
| for i := 0; i < 9; i++ { |
| if usageBits.At(i) != 0 { |
| usage |= 1 << uint(i) |
| } |
| } |
| out.KeyUsage = KeyUsage(usage) |
| |
| case 19: |
| // RFC 5280, 4.2.1.9 |
| var constraints basicConstraints |
| if rest, err := asn1.Unmarshal(e.Value, &constraints); err != nil { |
| return nil, err |
| } else if len(rest) != 0 { |
| return nil, errors.New("x509: trailing data after X.509 BasicConstraints") |
| } |
| |
| out.BasicConstraintsValid = true |
| out.IsCA = constraints.IsCA |
| out.MaxPathLen = constraints.MaxPathLen |
| out.MaxPathLenZero = out.MaxPathLen == 0 |
| // TODO: map out.MaxPathLen to 0 if it has the -1 default value? (Issue 19285) |
| case 17: |
| out.DNSNames, out.EmailAddresses, out.IPAddresses, out.URIs, err = parseSANExtension(e.Value) |
| if err != nil { |
| return nil, err |
| } |
| |
| if len(out.DNSNames) == 0 && len(out.EmailAddresses) == 0 && len(out.IPAddresses) == 0 && len(out.URIs) == 0 { |
| // If we didn't parse anything then we do the critical check, below. |
| unhandled = true |
| } |
| |
| case 30: |
| unhandled, err = parseNameConstraintsExtension(out, e) |
| if err != nil { |
| return nil, err |
| } |
| |
| case 31: |
| // RFC 5280, 4.2.1.13 |
| |
| // CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint |
| // |
| // DistributionPoint ::= SEQUENCE { |
| // distributionPoint [0] DistributionPointName OPTIONAL, |
| // reasons [1] ReasonFlags OPTIONAL, |
| // cRLIssuer [2] GeneralNames OPTIONAL } |
| // |
| // DistributionPointName ::= CHOICE { |
| // fullName [0] GeneralNames, |
| // nameRelativeToCRLIssuer [1] RelativeDistinguishedName } |
| |
| var cdp []distributionPoint |
| if rest, err := asn1.Unmarshal(e.Value, &cdp); err != nil { |
| return nil, err |
| } else if len(rest) != 0 { |
| return nil, errors.New("x509: trailing data after X.509 CRL distribution point") |
| } |
| |
| for _, dp := range cdp { |
| // Per RFC 5280, 4.2.1.13, one of distributionPoint or cRLIssuer may be empty. |
| if len(dp.DistributionPoint.FullName) == 0 { |
| continue |
| } |
| |
| for _, fullName := range dp.DistributionPoint.FullName { |
| if fullName.Tag == 6 { |
| out.CRLDistributionPoints = append(out.CRLDistributionPoints, string(fullName.Bytes)) |
| } |
| } |
| } |
| |
| case 35: |
| // RFC 5280, 4.2.1.1 |
| var a authKeyId |
| if rest, err := asn1.Unmarshal(e.Value, &a); err != nil { |
| return nil, err |
| } else if len(rest) != 0 { |
| return nil, errors.New("x509: trailing data after X.509 authority key-id") |
| } |
| out.AuthorityKeyId = a.Id |
| |
| case 37: |
| // RFC 5280, 4.2.1.12. Extended Key Usage |
| |
| // id-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-ce 37 } |
| // |
| // ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId |
| // |
| // KeyPurposeId ::= OBJECT IDENTIFIER |
| |
| var keyUsage []asn1.ObjectIdentifier |
| if rest, err := asn1.Unmarshal(e.Value, &keyUsage); err != nil { |
| return nil, err |
| } else if len(rest) != 0 { |
| return nil, errors.New("x509: trailing data after X.509 ExtendedKeyUsage") |
| } |
| |
| for _, u := range keyUsage { |
| if extKeyUsage, ok := extKeyUsageFromOID(u); ok { |
| out.ExtKeyUsage = append(out.ExtKeyUsage, extKeyUsage) |
| } else { |
| out.UnknownExtKeyUsage = append(out.UnknownExtKeyUsage, u) |
| } |
| } |
| |
| case 14: |
| // RFC 5280, 4.2.1.2 |
| var keyid []byte |
| if rest, err := asn1.Unmarshal(e.Value, &keyid); err != nil { |
| return nil, err |
| } else if len(rest) != 0 { |
| return nil, errors.New("x509: trailing data after X.509 key-id") |
| } |
| out.SubjectKeyId = keyid |
| |
| case 32: |
| // RFC 5280 4.2.1.4: Certificate Policies |
| var policies []policyInformation |
| if rest, err := asn1.Unmarshal(e.Value, &policies); err != nil { |
| return nil, err |
| } else if len(rest) != 0 { |
| return nil, errors.New("x509: trailing data after X.509 certificate policies") |
| } |
| out.PolicyIdentifiers = make([]asn1.ObjectIdentifier, len(policies)) |
| for i, policy := range policies { |
| out.PolicyIdentifiers[i] = policy.Policy |
| } |
| |
| default: |
| // Unknown extensions are recorded if critical. |
| unhandled = true |
| } |
| } else if e.Id.Equal(oidExtensionAuthorityInfoAccess) { |
| // RFC 5280 4.2.2.1: Authority Information Access |
| var aia []authorityInfoAccess |
| if rest, err := asn1.Unmarshal(e.Value, &aia); err != nil { |
| return nil, err |
| } else if len(rest) != 0 { |
| return nil, errors.New("x509: trailing data after X.509 authority information") |
| } |
| |
| for _, v := range aia { |
| // GeneralName: uniformResourceIdentifier [6] IA5String |
| if v.Location.Tag != 6 { |
| continue |
| } |
| if v.Method.Equal(oidAuthorityInfoAccessOcsp) { |
| out.OCSPServer = append(out.OCSPServer, string(v.Location.Bytes)) |
| } else if v.Method.Equal(oidAuthorityInfoAccessIssuers) { |
| out.IssuingCertificateURL = append(out.IssuingCertificateURL, string(v.Location.Bytes)) |
| } |
| } |
| } else { |
| // Unknown extensions are recorded if critical. |
| unhandled = true |
| } |
| |
| if e.Critical && unhandled { |
| out.UnhandledCriticalExtensions = append(out.UnhandledCriticalExtensions, e.Id) |
| } |
| } |
| |
| return out, nil |
| } |
| |
| // ParseCertificate parses a single certificate from the given ASN.1 DER data. |
| func ParseCertificate(asn1Data []byte) (*Certificate, error) { |
| var cert certificate |
| rest, err := asn1.Unmarshal(asn1Data, &cert) |
| if err != nil { |
| return nil, err |
| } |
| if len(rest) > 0 { |
| return nil, asn1.SyntaxError{Msg: "trailing data"} |
| } |
| |
| return parseCertificate(&cert) |
| } |
| |
| // ParseCertificates parses one or more certificates from the given ASN.1 DER |
| // data. The certificates must be concatenated with no intermediate padding. |
| func ParseCertificates(asn1Data []byte) ([]*Certificate, error) { |
| var v []*certificate |
| |
| for len(asn1Data) > 0 { |
| cert := new(certificate) |
| var err error |
| asn1Data, err = asn1.Unmarshal(asn1Data, cert) |
| if err != nil { |
| return nil, err |
| } |
| v = append(v, cert) |
| } |
| |
| ret := make([]*Certificate, len(v)) |
| for i, ci := range v { |
| cert, err := parseCertificate(ci) |
| if err != nil { |
| return nil, err |
| } |
| ret[i] = cert |
| } |
| |
| return ret, nil |
| } |
| |
| func reverseBitsInAByte(in byte) byte { |
| b1 := in>>4 | in<<4 |
| b2 := b1>>2&0x33 | b1<<2&0xcc |
| b3 := b2>>1&0x55 | b2<<1&0xaa |
| return b3 |
| } |
| |
| // asn1BitLength returns the bit-length of bitString by considering the |
| // most-significant bit in a byte to be the "first" bit. This convention |
| // matches ASN.1, but differs from almost everything else. |
| func asn1BitLength(bitString []byte) int { |
| bitLen := len(bitString) * 8 |
| |
| for i := range bitString { |
| b := bitString[len(bitString)-i-1] |
| |
| for bit := uint(0); bit < 8; bit++ { |
| if (b>>bit)&1 == 1 { |
| return bitLen |
| } |
| bitLen-- |
| } |
| } |
| |
| return 0 |
| } |
| |
| var ( |
| oidExtensionSubjectKeyId = []int{2, 5, 29, 14} |
| oidExtensionKeyUsage = []int{2, 5, 29, 15} |
| oidExtensionExtendedKeyUsage = []int{2, 5, 29, 37} |
| oidExtensionAuthorityKeyId = []int{2, 5, 29, 35} |
| oidExtensionBasicConstraints = []int{2, 5, 29, 19} |
| oidExtensionSubjectAltName = []int{2, 5, 29, 17} |
| oidExtensionCertificatePolicies = []int{2, 5, 29, 32} |
| oidExtensionNameConstraints = []int{2, 5, 29, 30} |
| oidExtensionCRLDistributionPoints = []int{2, 5, 29, 31} |
| oidExtensionAuthorityInfoAccess = []int{1, 3, 6, 1, 5, 5, 7, 1, 1} |
| ) |
| |
| var ( |
| oidAuthorityInfoAccessOcsp = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 1} |
| oidAuthorityInfoAccessIssuers = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 2} |
| ) |
| |
| // oidNotInExtensions returns whether an extension with the given oid exists in |
| // extensions. |
| func oidInExtensions(oid asn1.ObjectIdentifier, extensions []pkix.Extension) bool { |
| for _, e := range extensions { |
| if e.Id.Equal(oid) { |
| return true |
| } |
| } |
| return false |
| } |
| |
| // marshalSANs marshals a list of addresses into a the contents of an X.509 |
| // SubjectAlternativeName extension. |
| func marshalSANs(dnsNames, emailAddresses []string, ipAddresses []net.IP, uris []*url.URL) (derBytes []byte, err error) { |
| var rawValues []asn1.RawValue |
| for _, name := range dnsNames { |
| rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeDNS, Class: 2, Bytes: []byte(name)}) |
| } |
| for _, email := range emailAddresses { |
| rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeEmail, Class: 2, Bytes: []byte(email)}) |
| } |
| for _, rawIP := range ipAddresses { |
| // If possible, we always want to encode IPv4 addresses in 4 bytes. |
| ip := rawIP.To4() |
| if ip == nil { |
| ip = rawIP |
| } |
| rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeIP, Class: 2, Bytes: ip}) |
| } |
| for _, uri := range uris { |
| rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeURI, Class: 2, Bytes: []byte(uri.String())}) |
| } |
| return asn1.Marshal(rawValues) |
| } |
| |
| func isIA5String(s string) error { |
| for _, r := range s { |
| if r >= utf8.RuneSelf { |
| return fmt.Errorf("x509: %q cannot be encoded as an IA5String", s) |
| } |
| } |
| |
| return nil |
| } |
| |
| func buildExtensions(template *Certificate, subjectIsEmpty bool, authorityKeyId []byte) (ret []pkix.Extension, err error) { |
| ret = make([]pkix.Extension, 10 /* maximum number of elements. */) |
| n := 0 |
| |
| if template.KeyUsage != 0 && |
| !oidInExtensions(oidExtensionKeyUsage, template.ExtraExtensions) { |
| ret[n].Id = oidExtensionKeyUsage |
| ret[n].Critical = true |
| |
| var a [2]byte |
| a[0] = reverseBitsInAByte(byte(template.KeyUsage)) |
| a[1] = reverseBitsInAByte(byte(template.KeyUsage >> 8)) |
| |
| l := 1 |
| if a[1] != 0 { |
| l = 2 |
| } |
| |
| bitString := a[:l] |
| ret[n].Value, err = asn1.Marshal(asn1.BitString{Bytes: bitString, BitLength: asn1BitLength(bitString)}) |
| if err != nil { |
| return |
| } |
| n++ |
| } |
| |
| if (len(template.ExtKeyUsage) > 0 || len(template.UnknownExtKeyUsage) > 0) && |
| !oidInExtensions(oidExtensionExtendedKeyUsage, template.ExtraExtensions) { |
| ret[n].Id = oidExtensionExtendedKeyUsage |
| |
| var oids []asn1.ObjectIdentifier |
| for _, u := range template.ExtKeyUsage { |
| if oid, ok := oidFromExtKeyUsage(u); ok { |
| oids = append(oids, oid) |
| } else { |
| panic("internal error") |
| } |
| } |
| |
| oids = append(oids, template.UnknownExtKeyUsage...) |
| |
| ret[n].Value, err = asn1.Marshal(oids) |
| if err != nil { |
| return |
| } |
| n++ |
| } |
| |
| if template.BasicConstraintsValid && !oidInExtensions(oidExtensionBasicConstraints, template.ExtraExtensions) { |
| // Leaving MaxPathLen as zero indicates that no maximum path |
| // length is desired, unless MaxPathLenZero is set. A value of |
| // -1 causes encoding/asn1 to omit the value as desired. |
| maxPathLen := template.MaxPathLen |
| if maxPathLen == 0 && !template.MaxPathLenZero { |
| maxPathLen = -1 |
| } |
| ret[n].Id = oidExtensionBasicConstraints |
| ret[n].Value, err = asn1.Marshal(basicConstraints{template.IsCA, maxPathLen}) |
| ret[n].Critical = true |
| if err != nil { |
| return |
| } |
| n++ |
| } |
| |
| if len(template.SubjectKeyId) > 0 && !oidInExtensions(oidExtensionSubjectKeyId, template.ExtraExtensions) { |
| ret[n].Id = oidExtensionSubjectKeyId |
| ret[n].Value, err = asn1.Marshal(template.SubjectKeyId) |
| if err != nil { |
| return |
| } |
| n++ |
| } |
| |
| if len(authorityKeyId) > 0 && !oidInExtensions(oidExtensionAuthorityKeyId, template.ExtraExtensions) { |
| ret[n].Id = oidExtensionAuthorityKeyId |
| ret[n].Value, err = asn1.Marshal(authKeyId{authorityKeyId}) |
| if err != nil { |
| return |
| } |
| n++ |
| } |
| |
| if (len(template.OCSPServer) > 0 || len(template.IssuingCertificateURL) > 0) && |
| !oidInExtensions(oidExtensionAuthorityInfoAccess, template.ExtraExtensions) { |
| ret[n].Id = oidExtensionAuthorityInfoAccess |
| var aiaValues []authorityInfoAccess |
| for _, name := range template.OCSPServer { |
| aiaValues = append(aiaValues, authorityInfoAccess{ |
| Method: oidAuthorityInfoAccessOcsp, |
| Location: asn1.RawValue{Tag: 6, Class: 2, Bytes: []byte(name)}, |
| }) |
| } |
| for _, name := range template.IssuingCertificateURL { |
| aiaValues = append(aiaValues, authorityInfoAccess{ |
| Method: oidAuthorityInfoAccessIssuers, |
| Location: asn1.RawValue{Tag: 6, Class: 2, Bytes: []byte(name)}, |
| }) |
| } |
| ret[n].Value, err = asn1.Marshal(aiaValues) |
| if err != nil { |
| return |
| } |
| n++ |
| } |
| |
| if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0 || len(template.URIs) > 0) && |
| !oidInExtensions(oidExtensionSubjectAltName, template.ExtraExtensions) { |
| ret[n].Id = oidExtensionSubjectAltName |
| // https://tools.ietf.org/html/rfc5280#section-4.2.1.6 |
| // “If the subject field contains an empty sequence ... then |
| // subjectAltName extension ... is marked as critical” |
| ret[n].Critical = subjectIsEmpty |
| ret[n].Value, err = marshalSANs(template.DNSNames, template.EmailAddresses, template.IPAddresses, template.URIs) |
| if err != nil { |
| return |
| } |
| n++ |
| } |
| |
| if len(template.PolicyIdentifiers) > 0 && |
| !oidInExtensions(oidExtensionCertificatePolicies, template.ExtraExtensions) { |
| ret[n].Id = oidExtensionCertificatePolicies |
| policies := make([]policyInformation, len(template.PolicyIdentifiers)) |
| for i, policy := range template.PolicyIdentifiers { |
| policies[i].Policy = policy |
| } |
| ret[n].Value, err = asn1.Marshal(policies) |
| if err != nil { |
| return |
| } |
| n++ |
| } |
| |
| if (len(template.PermittedDNSDomains) > 0 || len(template.ExcludedDNSDomains) > 0 || |
| len(template.PermittedIPRanges) > 0 || len(template.ExcludedIPRanges) > 0 || |
| len(template.PermittedEmailAddresses) > 0 || len(template.ExcludedEmailAddresses) > 0 || |
| len(template.PermittedURIDomains) > 0 || len(template.ExcludedURIDomains) > 0) && |
| !oidInExtensions(oidExtensionNameConstraints, template.ExtraExtensions) { |
| ret[n].Id = oidExtensionNameConstraints |
| ret[n].Critical = template.PermittedDNSDomainsCritical |
| |
| ipAndMask := func(ipNet *net.IPNet) []byte { |
| maskedIP := ipNet.IP.Mask(ipNet.Mask) |
| ipAndMask := make([]byte, 0, len(maskedIP)+len(ipNet.Mask)) |
| ipAndMask = append(ipAndMask, maskedIP...) |
| ipAndMask = append(ipAndMask, ipNet.Mask...) |
| return ipAndMask |
| } |
| |
| serialiseConstraints := func(dns []string, ips []*net.IPNet, emails []string, uriDomains []string) (der []byte, err error) { |
| var b cryptobyte.Builder |
| |
| for _, name := range dns { |
| if err = isIA5String(name); err != nil { |
| return nil, err |
| } |
| |
| b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) { |
| b.AddASN1(cryptobyte_asn1.Tag(2).ContextSpecific(), func(b *cryptobyte.Builder) { |
| b.AddBytes([]byte(name)) |
| }) |
| }) |
| } |
| |
| for _, ipNet := range ips { |
| b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) { |
| b.AddASN1(cryptobyte_asn1.Tag(7).ContextSpecific(), func(b *cryptobyte.Builder) { |
| b.AddBytes(ipAndMask(ipNet)) |
| }) |
| }) |
| } |
| |
| for _, email := range emails { |
| if err = isIA5String(email); err != nil { |
| return nil, err |
| } |
| |
| b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) { |
| b.AddASN1(cryptobyte_asn1.Tag(1).ContextSpecific(), func(b *cryptobyte.Builder) { |
| b.AddBytes([]byte(email)) |
| }) |
| }) |
| } |
| |
| for _, uriDomain := range uriDomains { |
| if err = isIA5String(uriDomain); err != nil { |
| return nil, err |
| } |
| |
| b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) { |
| b.AddASN1(cryptobyte_asn1.Tag(6).ContextSpecific(), func(b *cryptobyte.Builder) { |
| b.AddBytes([]byte(uriDomain)) |
| }) |
| }) |
| } |
| |
| return b.Bytes() |
| } |
| |
| permitted, err := serialiseConstraints(template.PermittedDNSDomains, template.PermittedIPRanges, template.PermittedEmailAddresses, template.PermittedURIDomains) |
| if err != nil { |
| return nil, err |
| } |
| |
| excluded, err := serialiseConstraints(template.ExcludedDNSDomains, template.ExcludedIPRanges, template.ExcludedEmailAddresses, template.ExcludedURIDomains) |
| if err != nil { |
| return nil, err |
| } |
| |
| var b cryptobyte.Builder |
| b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) { |
| if len(permitted) > 0 { |
| b.AddASN1(cryptobyte_asn1.Tag(0).ContextSpecific().Constructed(), func(b *cryptobyte.Builder) { |
| b.AddBytes(permitted) |
| }) |
| } |
| |
| if len(excluded) > 0 { |
| b.AddASN1(cryptobyte_asn1.Tag(1).ContextSpecific().Constructed(), func(b *cryptobyte.Builder) { |
| b.AddBytes(excluded) |
| }) |
| } |
| }) |
| |
| ret[n].Value, err = b.Bytes() |
| if err != nil { |
| return nil, err |
| } |
| n++ |
| } |
| |
| if len(template.CRLDistributionPoints) > 0 && |
| !oidInExtensions(oidExtensionCRLDistributionPoints, template.ExtraExtensions) { |
| ret[n].Id = oidExtensionCRLDistributionPoints |
| |
| var crlDp []distributionPoint |
| for _, name := range template.CRLDistributionPoints { |
| dp := distributionPoint{ |
| DistributionPoint: distributionPointName{ |
| FullName: []asn1.RawValue{ |
| asn1.RawValue{Tag: 6, Class: 2, Bytes: []byte(name)}, |
| }, |
| }, |
| } |
| crlDp = append(crlDp, dp) |
| } |
| |
| ret[n].Value, err = asn1.Marshal(crlDp) |
| if err != nil { |
| return |
| } |
| n++ |
| } |
| |
| // Adding another extension here? Remember to update the maximum number |
| // of elements in the make() at the top of the function. |
| |
| return append(ret[:n], template.ExtraExtensions...), nil |
| } |
| |
| func subjectBytes(cert *Certificate) ([]byte, error) { |
| if len(cert.RawSubject) > 0 { |
| return cert.RawSubject, nil |
| } |
| |
| return asn1.Marshal(cert.Subject.ToRDNSequence()) |
| } |
| |
| // signingParamsForPublicKey returns the parameters to use for signing with |
| // priv. If requestedSigAlgo is not zero then it overrides the default |
| // signature algorithm. |
| func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo pkix.AlgorithmIdentifier, err error) { |
| var pubType PublicKeyAlgorithm |
| |
| switch pub := pub.(type) { |
| case *rsa.PublicKey: |
| pubType = RSA |
| hashFunc = crypto.SHA256 |
| sigAlgo.Algorithm = oidSignatureSHA256WithRSA |
| sigAlgo.Parameters = asn1.NullRawValue |
| |
| case *ecdsa.PublicKey: |
| pubType = ECDSA |
| |
| switch pub.Curve { |
| case elliptic.P224(), elliptic.P256(): |
| hashFunc = crypto.SHA256 |
| sigAlgo.Algorithm = oidSignatureECDSAWithSHA256 |
| case elliptic.P384(): |
| hashFunc = crypto.SHA384 |
| sigAlgo.Algorithm = oidSignatureECDSAWithSHA384 |
| case elliptic.P521(): |
| hashFunc = crypto.SHA512 |
| sigAlgo.Algorithm = oidSignatureECDSAWithSHA512 |
| default: |
| err = errors.New("x509: unknown elliptic curve") |
| } |
| |
| default: |
| err = errors.New("x509: only RSA and ECDSA keys supported") |
| } |
| |
| if err != nil { |
| return |
| } |
| |
| if requestedSigAlgo == 0 { |
| return |
| } |
| |
| found := false |
| for _, details := range signatureAlgorithmDetails { |
| if details.algo == requestedSigAlgo { |
| if details.pubKeyAlgo != pubType { |
| err = errors.New("x509: requested SignatureAlgorithm does not match private key type") |
| return |
| } |
| sigAlgo.Algorithm, hashFunc = details.oid, details.hash |
| if hashFunc == 0 { |
| err = errors.New("x509: cannot sign with hash function requested") |
| return |
| } |
| if requestedSigAlgo.isRSAPSS() { |
| sigAlgo.Parameters = rsaPSSParameters(hashFunc) |
| } |
| found = true |
| break |
| } |
| } |
| |
| if !found { |
| err = errors.New("x509: unknown SignatureAlgorithm") |
| } |
| |
| return |
| } |
| |
| // emptyASN1Subject is the ASN.1 DER encoding of an empty Subject, which is |
| // just an empty SEQUENCE. |
| var emptyASN1Subject = []byte{0x30, 0} |
| |
| // CreateCertificate creates a new X.509v3 certificate based on a template. |
| // The following members of template are used: AuthorityKeyId, |
| // BasicConstraintsValid, DNSNames, ExcludedDNSDomains, ExtKeyUsage, |
| // IsCA, KeyUsage, MaxPathLen, MaxPathLenZero, NotAfter, NotBefore, |
| // PermittedDNSDomains, PermittedDNSDomainsCritical, SerialNumber, |
| // SignatureAlgorithm, Subject, SubjectKeyId, and UnknownExtKeyUsage. |
| // |
| // The certificate is signed by parent. If parent is equal to template then the |
| // certificate is self-signed. The parameter pub is the public key of the |
| // signee and priv is the private key of the signer. |
| // |
| // The returned slice is the certificate in DER encoding. |
| // |
| // All keys types that are implemented via crypto.Signer are supported (This |
| // includes *rsa.PublicKey and *ecdsa.PublicKey.) |
| // |
| // The AuthorityKeyId will be taken from the SubjectKeyId of parent, if any, |
| // unless the resulting certificate is self-signed. Otherwise the value from |
| // template will be used. |
| func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv interface{}) (cert []byte, err error) { |
| key, ok := priv.(crypto.Signer) |
| if !ok { |
| return nil, errors.New("x509: certificate private key does not implement crypto.Signer") |
| } |
| |
| if template.SerialNumber == nil { |
| return nil, errors.New("x509: no SerialNumber given") |
| } |
| |
| hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm) |
| if err != nil { |
| return nil, err |
| } |
| |
| publicKeyBytes, publicKeyAlgorithm, err := marshalPublicKey(pub) |
| if err != nil { |
| return nil, err |
| } |
| |
| asn1Issuer, err := subjectBytes(parent) |
| if err != nil { |
| return |
| } |
| |
| asn1Subject, err := subjectBytes(template) |
| if err != nil { |
| return |
| } |
| |
| authorityKeyId := template.AuthorityKeyId |
| if !bytes.Equal(asn1Issuer, asn1Subject) && len(parent.SubjectKeyId) > 0 { |
| authorityKeyId = parent.SubjectKeyId |
| } |
| |
| extensions, err := buildExtensions(template, bytes.Equal(asn1Subject, emptyASN1Subject), authorityKeyId) |
| if err != nil { |
| return |
| } |
| |
| encodedPublicKey := asn1.BitString{BitLength: len(publicKeyBytes) * 8, Bytes: publicKeyBytes} |
| c := tbsCertificate{ |
| Version: 2, |
| SerialNumber: template.SerialNumber, |
| SignatureAlgorithm: signatureAlgorithm, |
| Issuer: asn1.RawValue{FullBytes: asn1Issuer}, |
| Validity: validity{template.NotBefore.UTC(), template.NotAfter.UTC()}, |
| Subject: asn1.RawValue{FullBytes: asn1Subject}, |
| PublicKey: publicKeyInfo{nil, publicKeyAlgorithm, encodedPublicKey}, |
| Extensions: extensions, |
| } |
| |
| tbsCertContents, err := asn1.Marshal(c) |
| if err != nil { |
| return |
| } |
| |
| c.Raw = tbsCertContents |
| |
| h := hashFunc.New() |
| h.Write(tbsCertContents) |
| digest := h.Sum(nil) |
| |
| var signerOpts crypto.SignerOpts |
| signerOpts = hashFunc |
| if template.SignatureAlgorithm != 0 && template.SignatureAlgorithm.isRSAPSS() { |
| signerOpts = &rsa.PSSOptions{ |
| SaltLength: rsa.PSSSaltLengthEqualsHash, |
| Hash: hashFunc, |
| } |
| } |
| |
| var signature []byte |
| signature, err = key.Sign(rand, digest, signerOpts) |
| if err != nil { |
| return |
| } |
| |
| return asn1.Marshal(certificate{ |
| nil, |
| c, |
| signatureAlgorithm, |
| asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, |
| }) |
| } |
| |
| // pemCRLPrefix is the magic string that indicates that we have a PEM encoded |
| // CRL. |
| var pemCRLPrefix = []byte("-----BEGIN X509 CRL") |
| |
| // pemType is the type of a PEM encoded CRL. |
| var pemType = "X509 CRL" |
| |
| // ParseCRL parses a CRL from the given bytes. It's often the case that PEM |
| // encoded CRLs will appear where they should be DER encoded, so this function |
| // will transparently handle PEM encoding as long as there isn't any leading |
| // garbage. |
| func ParseCRL(crlBytes []byte) (*pkix.CertificateList, error) { |
| if bytes.HasPrefix(crlBytes, pemCRLPrefix) { |
| block, _ := pem.Decode(crlBytes) |
| if block != nil && block.Type == pemType { |
| crlBytes = block.Bytes |
| } |
| } |
| return ParseDERCRL(crlBytes) |
| } |
| |
| // ParseDERCRL parses a DER encoded CRL from the given bytes. |
| func ParseDERCRL(derBytes []byte) (*pkix.CertificateList, error) { |
| certList := new(pkix.CertificateList) |
| if rest, err := asn1.Unmarshal(derBytes, certList); err != nil { |
| return nil, err |
| } else if len(rest) != 0 { |
| return nil, errors.New("x509: trailing data after CRL") |
| } |
| return certList, nil |
| } |
| |
| // CreateCRL returns a DER encoded CRL, signed by this Certificate, that |
| // contains the given list of revoked certificates. |
| func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts []pkix.RevokedCertificate, now, expiry time.Time) (crlBytes []byte, err error) { |
| key, ok := priv.(crypto.Signer) |
| if !ok { |
| return nil, errors.New("x509: certificate private key does not implement crypto.Signer") |
| } |
| |
| hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), 0) |
| if err != nil { |
| return nil, err |
| } |
| |
| // Force revocation times to UTC per RFC 5280. |
| revokedCertsUTC := make([]pkix.RevokedCertificate, len(revokedCerts)) |
| for i, rc := range revokedCerts { |
| rc.RevocationTime = rc.RevocationTime.UTC() |
| revokedCertsUTC[i] = rc |
| } |
| |
| tbsCertList := pkix.TBSCertificateList{ |
| Version: 1, |
| Signature: signatureAlgorithm, |
| Issuer: c.Subject.ToRDNSequence(), |
| ThisUpdate: now.UTC(), |
| NextUpdate: expiry.UTC(), |
| RevokedCertificates: revokedCertsUTC, |
| } |
| |
| // Authority Key Id |
| if len(c.SubjectKeyId) > 0 { |
| var aki pkix.Extension |
| aki.Id = oidExtensionAuthorityKeyId |
| aki.Value, err = asn1.Marshal(authKeyId{Id: c.SubjectKeyId}) |
| if err != nil { |
| return |
| } |
| tbsCertList.Extensions = append(tbsCertList.Extensions, aki) |
| } |
| |
| tbsCertListContents, err := asn1.Marshal(tbsCertList) |
| if err != nil { |
| return |
| } |
| |
| h := hashFunc.New() |
| h.Write(tbsCertListContents) |
| digest := h.Sum(nil) |
| |
| var signature []byte |
| signature, err = key.Sign(rand, digest, hashFunc) |
| if err != nil { |
| return |
| } |
| |
| return asn1.Marshal(pkix.CertificateList{ |
| TBSCertList: tbsCertList, |
| SignatureAlgorithm: signatureAlgorithm, |
| SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, |
| }) |
| } |
| |
| // CertificateRequest represents a PKCS #10, certificate signature request. |
| type CertificateRequest struct { |
| Raw []byte // Complete ASN.1 DER content (CSR, signature algorithm and signature). |
| RawTBSCertificateRequest []byte // Certificate request info part of raw ASN.1 DER content. |
| RawSubjectPublicKeyInfo []byte // DER encoded SubjectPublicKeyInfo. |
| RawSubject []byte // DER encoded Subject. |
| |
| Version int |
| Signature []byte |
| SignatureAlgorithm SignatureAlgorithm |
| |
| PublicKeyAlgorithm PublicKeyAlgorithm |
| PublicKey interface{} |
| |
| Subject pkix.Name |
| |
| // Attributes is the dried husk of a bug and shouldn't be used. |
| Attributes []pkix.AttributeTypeAndValueSET |
| |
| // Extensions contains raw X.509 extensions. When parsing CSRs, this |
| // can be used to extract extensions that are not parsed by this |
| // package. |
| Extensions []pkix.Extension |
| |
| // ExtraExtensions contains extensions to be copied, raw, into any |
| // marshaled CSR. Values override any extensions that would otherwise |
| // be produced based on the other fields but are overridden by any |
| // extensions specified in Attributes. |
| // |
| // The ExtraExtensions field is not populated when parsing CSRs, see |
| // Extensions. |
| ExtraExtensions []pkix.Extension |
| |
| // Subject Alternate Name values. |
| DNSNames []string |
| EmailAddresses []string |
| IPAddresses []net.IP |
| URIs []*url.URL |
| } |
| |
| // These structures reflect the ASN.1 structure of X.509 certificate |
| // signature requests (see RFC 2986): |
| |
| type tbsCertificateRequest struct { |
| Raw asn1.RawContent |
| Version int |
| Subject asn1.RawValue |
| PublicKey publicKeyInfo |
| RawAttributes []asn1.RawValue `asn1:"tag:0"` |
| } |
| |
| type certificateRequest struct { |
| Raw asn1.RawContent |
| TBSCSR tbsCertificateRequest |
| SignatureAlgorithm pkix.AlgorithmIdentifier |
| SignatureValue asn1.BitString |
| } |
| |
| // oidExtensionRequest is a PKCS#9 OBJECT IDENTIFIER that indicates requested |
| // extensions in a CSR. |
| var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14} |
| |
| // newRawAttributes converts AttributeTypeAndValueSETs from a template |
| // CertificateRequest's Attributes into tbsCertificateRequest RawAttributes. |
| func newRawAttributes(attributes []pkix.AttributeTypeAndValueSET) ([]asn1.RawValue, error) { |
| var rawAttributes []asn1.RawValue |
| b, err := asn1.Marshal(attributes) |
| if err != nil { |
| return nil, err |
| } |
| rest, err := asn1.Unmarshal(b, &rawAttributes) |
| if err != nil { |
| return nil, err |
| } |
| if len(rest) != 0 { |
| return nil, errors.New("x509: failed to unmarshal raw CSR Attributes") |
| } |
| return rawAttributes, nil |
| } |
| |
| // parseRawAttributes Unmarshals RawAttributes intos AttributeTypeAndValueSETs. |
| func parseRawAttributes(rawAttributes []asn1.RawValue) []pkix.AttributeTypeAndValueSET { |
| var attributes []pkix.AttributeTypeAndValueSET |
| for _, rawAttr := range rawAttributes { |
| var attr pkix.AttributeTypeAndValueSET |
| rest, err := asn1.Unmarshal(rawAttr.FullBytes, &attr) |
| // Ignore attributes that don't parse into pkix.AttributeTypeAndValueSET |
| // (i.e.: challengePassword or unstructuredName). |
| if err == nil && len(rest) == 0 { |
| attributes = append(attributes, attr) |
| } |
| } |
| return attributes |
| } |
| |
| // parseCSRExtensions parses the attributes from a CSR and extracts any |
| // requested extensions. |
| func parseCSRExtensions(rawAttributes []asn1.RawValue) ([]pkix.Extension, error) { |
| // pkcs10Attribute reflects the Attribute structure from section 4.1 of |
| // https://tools.ietf.org/html/rfc2986. |
| type pkcs10Attribute struct { |
| Id asn1.ObjectIdentifier |
| Values []asn1.RawValue `asn1:"set"` |
| } |
| |
| var ret []pkix.Extension |
| for _, rawAttr := range rawAttributes { |
| var attr pkcs10Attribute |
| if rest, err := asn1.Unmarshal(rawAttr.FullBytes, &attr); err != nil || len(rest) != 0 || len(attr.Values) == 0 { |
| // Ignore attributes that don't parse. |
| continue |
| } |
| |
| if !attr.Id.Equal(oidExtensionRequest) { |
| continue |
| } |
| |
| var extensions []pkix.Extension |
| if _, err := asn1.Unmarshal(attr.Values[0].FullBytes, &extensions); err != nil { |
| return nil, err |
| } |
| ret = append(ret, extensions...) |
| } |
| |
| return ret, nil |
| } |
| |
| // CreateCertificateRequest creates a new certificate request based on a |
| // template. The following members of template are used: Attributes, DNSNames, |
| // EmailAddresses, ExtraExtensions, IPAddresses, URIs, SignatureAlgorithm, and |
| // Subject. The private key is the private key of the signer. |
| // |
| // The returned slice is the certificate request in DER encoding. |
| // |
| // All keys types that are implemented via crypto.Signer are supported (This |
| // includes *rsa.PublicKey and *ecdsa.PublicKey.) |
| func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv interface{}) (csr []byte, err error) { |
| key, ok := priv.(crypto.Signer) |
| if !ok { |
| return nil, errors.New("x509: certificate private key does not implement crypto.Signer") |
| } |
| |
| var hashFunc crypto.Hash |
| var sigAlgo pkix.AlgorithmIdentifier |
| hashFunc, sigAlgo, err = signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm) |
| if err != nil { |
| return nil, err |
| } |
| |
| var publicKeyBytes []byte |
| var publicKeyAlgorithm pkix.AlgorithmIdentifier |
| publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(key.Public()) |
| if err != nil { |
| return nil, err |
| } |
| |
| var extensions []pkix.Extension |
| |
| if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0 || len(template.URIs) > 0) && |
| !oidInExtensions(oidExtensionSubjectAltName, template.ExtraExtensions) { |
| sanBytes, err := marshalSANs(template.DNSNames, template.EmailAddresses, template.IPAddresses, template.URIs) |
| if err != nil { |
| return nil, err |
| } |
| |
| extensions = append(extensions, pkix.Extension{ |
| Id: oidExtensionSubjectAltName, |
| Value: sanBytes, |
| }) |
| } |
| |
| extensions = append(extensions, template.ExtraExtensions...) |
| |
| var attributes []pkix.AttributeTypeAndValueSET |
| attributes = append(attributes, template.Attributes...) |
| |
| if len(extensions) > 0 { |
| // specifiedExtensions contains all the extensions that we |
| // found specified via template.Attributes. |
| specifiedExtensions := make(map[string]bool) |
| |
| for _, atvSet := range template.Attributes { |
| if !atvSet.Type.Equal(oidExtensionRequest) { |
| continue |
| } |
| |
| for _, atvs := range atvSet.Value { |
| for _, atv := range atvs { |
| specifiedExtensions[atv.Type.String()] = true |
| } |
| } |
| } |
| |
| atvs := make([]pkix.AttributeTypeAndValue, 0, len(extensions)) |
| for _, e := range extensions { |
| if specifiedExtensions[e.Id.String()] { |
| // Attributes already contained a value for |
| // this extension and it takes priority. |
| continue |
| } |
| |
| atvs = append(atvs, pkix.AttributeTypeAndValue{ |
| // There is no place for the critical flag in a CSR. |
| Type: e.Id, |
| Value: e.Value, |
| }) |
| } |
| |
| // Append the extensions to an existing attribute if possible. |
| appended := false |
| for _, atvSet := range attributes { |
| if !atvSet.Type.Equal(oidExtensionRequest) || len(atvSet.Value) == 0 { |
| continue |
| } |
| |
| atvSet.Value[0] = append(atvSet.Value[0], atvs...) |
| appended = true |
| break |
| } |
| |
| // Otherwise, add a new attribute for the extensions. |
| if !appended { |
| attributes = append(attributes, pkix.AttributeTypeAndValueSET{ |
| Type: oidExtensionRequest, |
| Value: [][]pkix.AttributeTypeAndValue{ |
| atvs, |
| }, |
| }) |
| } |
| } |
| |
| asn1Subject := template.RawSubject |
| if len(asn1Subject) == 0 { |
| asn1Subject, err = asn1.Marshal(template.Subject.ToRDNSequence()) |
| if err != nil { |
| return |
| } |
| } |
| |
| rawAttributes, err := newRawAttributes(attributes) |
| if err != nil { |
| return |
| } |
| |
| tbsCSR := tbsCertificateRequest{ |
| Version: 0, // PKCS #10, RFC 2986 |
| Subject: asn1.RawValue{FullBytes: asn1Subject}, |
| PublicKey: publicKeyInfo{ |
| Algorithm: publicKeyAlgorithm, |
| PublicKey: asn1.BitString{ |
| Bytes: publicKeyBytes, |
| BitLength: len(publicKeyBytes) * 8, |
| }, |
| }, |
| RawAttributes: rawAttributes, |
| } |
| |
| tbsCSRContents, err := asn1.Marshal(tbsCSR) |
| if err != nil { |
| return |
| } |
| tbsCSR.Raw = tbsCSRContents |
| |
| h := hashFunc.New() |
| h.Write(tbsCSRContents) |
| digest := h.Sum(nil) |
| |
| var signature []byte |
| signature, err = key.Sign(rand, digest, hashFunc) |
| if err != nil { |
| return |
| } |
| |
| return asn1.Marshal(certificateRequest{ |
| TBSCSR: tbsCSR, |
| SignatureAlgorithm: sigAlgo, |
| SignatureValue: asn1.BitString{ |
| Bytes: signature, |
| BitLength: len(signature) * 8, |
| }, |
| }) |
| } |
| |
| // ParseCertificateRequest parses a single certificate request from the |
| // given ASN.1 DER data. |
| func ParseCertificateRequest(asn1Data []byte) (*CertificateRequest, error) { |
| var csr certificateRequest |
| |
| rest, err := asn1.Unmarshal(asn1Data, &csr) |
| if err != nil { |
| return nil, err |
| } else if len(rest) != 0 { |
| return nil, asn1.SyntaxError{Msg: "trailing data"} |
| } |
| |
| return parseCertificateRequest(&csr) |
| } |
| |
| func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error) { |
| out := &CertificateRequest{ |
| Raw: in.Raw, |
| RawTBSCertificateRequest: in.TBSCSR.Raw, |
| RawSubjectPublicKeyInfo: in.TBSCSR.PublicKey.Raw, |
| RawSubject: in.TBSCSR.Subject.FullBytes, |
| |
| Signature: in.SignatureValue.RightAlign(), |
| SignatureAlgorithm: getSignatureAlgorithmFromAI(in.SignatureAlgorithm), |
| |
| PublicKeyAlgorithm: getPublicKeyAlgorithmFromOID(in.TBSCSR.PublicKey.Algorithm.Algorithm), |
| |
| Version: in.TBSCSR.Version, |
| Attributes: parseRawAttributes(in.TBSCSR.RawAttributes), |
| } |
| |
| var err error |
| out.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, &in.TBSCSR.PublicKey) |
| if err != nil { |
| return nil, err |
| } |
| |
| var subject pkix.RDNSequence |
| if rest, err := asn1.Unmarshal(in.TBSCSR.Subject.FullBytes, &subject); err != nil { |
| return nil, err |
| } else if len(rest) != 0 { |
| return nil, errors.New("x509: trailing data after X.509 Subject") |
| } |
| |
| out.Subject.FillFromRDNSequence(&subject) |
| |
| if out.Extensions, err = parseCSRExtensions(in.TBSCSR.RawAttributes); err != nil { |
| return nil, err |
| } |
| |
| for _, extension := range out.Extensions { |
| if extension.Id.Equal(oidExtensionSubjectAltName) { |
| out.DNSNames, out.EmailAddresses, out.IPAddresses, out.URIs, err = parseSANExtension(extension.Value) |
| if err != nil { |
| return nil, err |
| } |
| } |
| } |
| |
| return out, nil |
| } |
| |
| // CheckSignature reports whether the signature on c is valid. |
| func (c *CertificateRequest) CheckSignature() error { |
| return checkSignature(c.SignatureAlgorithm, c.RawTBSCertificateRequest, c.Signature, c.PublicKey) |
| } |