| // 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. |
| package x509 |
| |
| import ( |
| "asn1" |
| "big" |
| "bytes" |
| "crypto" |
| "crypto/dsa" |
| "crypto/rsa" |
| "crypto/sha1" |
| "crypto/x509/pkix" |
| "encoding/pem" |
| "io" |
| "os" |
| "time" |
| ) |
| |
| // pkcs1PrivateKey is a structure which mirrors the PKCS#1 ASN.1 for an RSA private key. |
| type pkcs1PrivateKey struct { |
| Version int |
| N *big.Int |
| E int |
| D *big.Int |
| P *big.Int |
| Q *big.Int |
| // We ignore these values, if present, because rsa will calculate them. |
| Dp *big.Int `asn1:"optional"` |
| Dq *big.Int `asn1:"optional"` |
| Qinv *big.Int `asn1:"optional"` |
| |
| AdditionalPrimes []pkcs1AdditionalRSAPrime `asn1:"optional"` |
| } |
| |
| type pkcs1AdditionalRSAPrime struct { |
| Prime *big.Int |
| |
| // We ignore these values because rsa will calculate them. |
| Exp *big.Int |
| Coeff *big.Int |
| } |
| |
| // ParsePKCS1PrivateKey returns an RSA private key from its ASN.1 PKCS#1 DER encoded form. |
| func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err os.Error) { |
| var priv pkcs1PrivateKey |
| rest, err := asn1.Unmarshal(der, &priv) |
| if len(rest) > 0 { |
| err = asn1.SyntaxError{"trailing data"} |
| return |
| } |
| if err != nil { |
| return |
| } |
| |
| if priv.Version > 1 { |
| return nil, os.NewError("x509: unsupported private key version") |
| } |
| |
| if priv.N.Sign() <= 0 || priv.D.Sign() <= 0 || priv.P.Sign() <= 0 || priv.Q.Sign() <= 0 { |
| return nil, os.NewError("private key contains zero or negative value") |
| } |
| |
| key = new(rsa.PrivateKey) |
| key.PublicKey = rsa.PublicKey{ |
| E: priv.E, |
| N: priv.N, |
| } |
| |
| key.D = priv.D |
| key.Primes = make([]*big.Int, 2+len(priv.AdditionalPrimes)) |
| key.Primes[0] = priv.P |
| key.Primes[1] = priv.Q |
| for i, a := range priv.AdditionalPrimes { |
| if a.Prime.Sign() <= 0 { |
| return nil, os.NewError("private key contains zero or negative prime") |
| } |
| key.Primes[i+2] = a.Prime |
| // We ignore the other two values because rsa will calculate |
| // them as needed. |
| } |
| |
| err = key.Validate() |
| if err != nil { |
| return nil, err |
| } |
| key.Precompute() |
| |
| return |
| } |
| |
| // MarshalPKCS1PrivateKey converts a private key to ASN.1 DER encoded form. |
| func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte { |
| key.Precompute() |
| |
| version := 0 |
| if len(key.Primes) > 2 { |
| version = 1 |
| } |
| |
| priv := pkcs1PrivateKey{ |
| Version: version, |
| N: key.N, |
| E: key.PublicKey.E, |
| D: key.D, |
| P: key.Primes[0], |
| Q: key.Primes[1], |
| Dp: key.Precomputed.Dp, |
| Dq: key.Precomputed.Dq, |
| Qinv: key.Precomputed.Qinv, |
| } |
| |
| priv.AdditionalPrimes = make([]pkcs1AdditionalRSAPrime, len(key.Precomputed.CRTValues)) |
| for i, values := range key.Precomputed.CRTValues { |
| priv.AdditionalPrimes[i].Prime = key.Primes[2+i] |
| priv.AdditionalPrimes[i].Exp = values.Exp |
| priv.AdditionalPrimes[i].Coeff = values.Coeff |
| } |
| |
| b, _ := asn1.Marshal(priv) |
| return b |
| } |
| |
| // 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:1,tag:0"` |
| SerialNumber *big.Int |
| SignatureAlgorithm pkix.AlgorithmIdentifier |
| Issuer pkix.RDNSequence |
| Validity validity |
| Subject pkix.RDNSequence |
| 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 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 |
| ) |
| |
| type PublicKeyAlgorithm int |
| |
| const ( |
| UnknownPublicKeyAlgorithm PublicKeyAlgorithm = iota |
| RSA |
| DSA |
| ) |
| |
| // 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 IDENTIFER ::= { 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 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 |
| // |
| // dsaWithSha356 OBJECT IDENTIFER ::= { |
| // joint-iso-ccitt(2) country(16) us(840) organization(1) gov(101) |
| // algorithms(4) id-dsa-with-sha2(3) 2} |
| // |
| 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} |
| oidSignatureDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3} |
| oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 4, 3, 2} |
| ) |
| |
| func getSignatureAlgorithmFromOID(oid asn1.ObjectIdentifier) SignatureAlgorithm { |
| switch { |
| case oid.Equal(oidSignatureMD2WithRSA): |
| return MD2WithRSA |
| case oid.Equal(oidSignatureMD5WithRSA): |
| return MD5WithRSA |
| case oid.Equal(oidSignatureSHA1WithRSA): |
| return SHA1WithRSA |
| case oid.Equal(oidSignatureSHA256WithRSA): |
| return SHA256WithRSA |
| case oid.Equal(oidSignatureSHA384WithRSA): |
| return SHA384WithRSA |
| case oid.Equal(oidSignatureSHA512WithRSA): |
| return SHA512WithRSA |
| case oid.Equal(oidSignatureDSAWithSHA1): |
| return DSAWithSHA1 |
| case oid.Equal(oidSignatureDSAWithSHA256): |
| return DSAWithSHA256 |
| } |
| 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 } |
| var ( |
| oidPublicKeyRsa = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1} |
| oidPublicKeyDsa = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1} |
| ) |
| |
| func getPublicKeyAlgorithmFromOID(oid asn1.ObjectIdentifier) PublicKeyAlgorithm { |
| switch { |
| case oid.Equal(oidPublicKeyRsa): |
| return RSA |
| case oid.Equal(oidPublicKeyDsa): |
| return DSA |
| } |
| return UnknownPublicKeyAlgorithm |
| } |
| |
| // 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} |
| oidExtKeyUsageTimeStamping = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8} |
| oidExtKeyUsageOCSPSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9} |
| ) |
| |
| // 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 |
| ExtKeyUsageTimeStamping |
| ExtKeyUsageOCSPSigning |
| ) |
| |
| // 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. |
| |
| 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 |
| |
| ExtKeyUsage []ExtKeyUsage // Sequence of extended key usages. |
| UnknownExtKeyUsage []asn1.ObjectIdentifier // Encountered extended key usages unknown to this package. |
| |
| BasicConstraintsValid bool // if true then the next two fields are valid. |
| IsCA bool |
| MaxPathLen int |
| |
| SubjectKeyId []byte |
| AuthorityKeyId []byte |
| |
| // Subject Alternate Name values |
| DNSNames []string |
| EmailAddresses []string |
| |
| // Name constraints |
| PermittedDNSDomainsCritical bool // if true then the name constraints are marked critical. |
| PermittedDNSDomains []string |
| |
| PolicyIdentifiers []asn1.ObjectIdentifier |
| } |
| |
| // UnsupportedAlgorithmError results from attempting to perform an operation |
| // that involves algorithms that are not currently implemented. |
| type UnsupportedAlgorithmError struct{} |
| |
| func (UnsupportedAlgorithmError) String() string { |
| return "cannot verify signature: algorithm unimplemented" |
| } |
| |
| // 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) String() string { |
| return "invalid signature: parent certificate cannot sign this kind of certificate" |
| } |
| |
| func (c *Certificate) Equal(other *Certificate) bool { |
| return bytes.Equal(c.Raw, other.Raw) |
| } |
| |
| // CheckSignatureFrom verifies that the signature on c is a valid signature |
| // from parent. |
| func (c *Certificate) CheckSignatureFrom(parent *Certificate) (err os.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." |
| if parent.Version == 3 && !parent.BasicConstraintsValid || |
| parent.BasicConstraintsValid && !parent.IsCA { |
| return ConstraintViolationError{} |
| } |
| |
| if parent.KeyUsage != 0 && parent.KeyUsage&KeyUsageCertSign == 0 { |
| return ConstraintViolationError{} |
| } |
| |
| if parent.PublicKeyAlgorithm == UnknownPublicKeyAlgorithm { |
| return UnsupportedAlgorithmError{} |
| } |
| |
| // 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) (err os.Error) { |
| var hashType crypto.Hash |
| |
| switch algo { |
| case SHA1WithRSA, DSAWithSHA1: |
| hashType = crypto.SHA1 |
| case SHA256WithRSA, DSAWithSHA256: |
| hashType = crypto.SHA256 |
| case SHA384WithRSA: |
| hashType = crypto.SHA384 |
| case SHA512WithRSA: |
| hashType = crypto.SHA512 |
| default: |
| return UnsupportedAlgorithmError{} |
| } |
| |
| h := hashType.New() |
| if h == nil { |
| return UnsupportedAlgorithmError{} |
| } |
| |
| h.Write(signed) |
| digest := h.Sum() |
| |
| switch pub := c.PublicKey.(type) { |
| case *rsa.PublicKey: |
| return rsa.VerifyPKCS1v15(pub, hashType, digest, signature) |
| case *dsa.PublicKey: |
| dsaSig := new(dsaSignature) |
| if _, err := asn1.Unmarshal(signature, dsaSig); err != nil { |
| return err |
| } |
| if dsaSig.R.Sign() <= 0 || dsaSig.S.Sign() <= 0 { |
| return os.NewError("DSA signature contained zero or negative values") |
| } |
| if !dsa.Verify(pub, digest, dsaSig.R, dsaSig.S) { |
| return os.NewError("DSA verification failure") |
| } |
| return |
| } |
| return UnsupportedAlgorithmError{} |
| } |
| |
| // CheckCRLSignature checks that the signature in crl is from c. |
| func (c *Certificate) CheckCRLSignature(crl *pkix.CertificateList) (err os.Error) { |
| algo := getSignatureAlgorithmFromOID(crl.SignatureAlgorithm.Algorithm) |
| return c.CheckSignature(algo, crl.TBSCertList.Raw, crl.SignatureValue.RightAlign()) |
| } |
| |
| type UnhandledCriticalExtension struct{} |
| |
| func (h UnhandledCriticalExtension) String() string { |
| return "unhandled critical extension" |
| } |
| |
| type basicConstraints struct { |
| IsCA bool `asn1:"optional"` |
| MaxPathLen int `asn1:"optional"` |
| } |
| |
| type rsaPublicKey struct { |
| N *big.Int |
| E int |
| } |
| |
| // RFC 5280 4.2.1.4 |
| type policyInformation struct { |
| Policy asn1.ObjectIdentifier |
| // policyQualifiers omitted |
| } |
| |
| // RFC 5280, 4.2.1.10 |
| type nameConstraints struct { |
| Permitted []generalSubtree `asn1:"optional,tag:0"` |
| Excluded []generalSubtree `asn1:"optional,tag:1"` |
| } |
| |
| type generalSubtree struct { |
| Name string `asn1:"tag:2,optional,ia5"` |
| Min int `asn1:"optional,tag:0"` |
| Max int `asn1:"optional,tag:1"` |
| } |
| |
| func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{}, os.Error) { |
| asn1Data := keyData.PublicKey.RightAlign() |
| switch algo { |
| case RSA: |
| p := new(rsaPublicKey) |
| _, err := asn1.Unmarshal(asn1Data, p) |
| if err != nil { |
| return nil, err |
| } |
| |
| pub := &rsa.PublicKey{ |
| E: p.E, |
| N: p.N, |
| } |
| return pub, nil |
| case DSA: |
| var p *big.Int |
| _, err := asn1.Unmarshal(asn1Data, &p) |
| if err != nil { |
| return nil, err |
| } |
| paramsData := keyData.Algorithm.Parameters.FullBytes |
| params := new(dsaAlgorithmParameters) |
| _, err = asn1.Unmarshal(paramsData, params) |
| if err != nil { |
| return nil, err |
| } |
| if p.Sign() <= 0 || params.P.Sign() <= 0 || params.Q.Sign() <= 0 || params.G.Sign() <= 0 { |
| return nil, os.NewError("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 |
| default: |
| return nil, nil |
| } |
| panic("unreachable") |
| } |
| |
| func parseCertificate(in *certificate) (*Certificate, os.Error) { |
| out := new(Certificate) |
| out.Raw = in.Raw |
| out.RawTBSCertificate = in.TBSCertificate.Raw |
| out.RawSubjectPublicKeyInfo = in.TBSCertificate.PublicKey.Raw |
| |
| out.Signature = in.SignatureValue.RightAlign() |
| out.SignatureAlgorithm = |
| getSignatureAlgorithmFromOID(in.TBSCertificate.SignatureAlgorithm.Algorithm) |
| |
| out.PublicKeyAlgorithm = |
| getPublicKeyAlgorithmFromOID(in.TBSCertificate.PublicKey.Algorithm.Algorithm) |
| var err os.Error |
| out.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, &in.TBSCertificate.PublicKey) |
| if err != nil { |
| return nil, err |
| } |
| |
| if in.TBSCertificate.SerialNumber.Sign() < 0 { |
| return nil, os.NewError("negative serial number") |
| } |
| |
| out.Version = in.TBSCertificate.Version + 1 |
| out.SerialNumber = in.TBSCertificate.SerialNumber |
| out.Issuer.FillFromRDNSequence(&in.TBSCertificate.Issuer) |
| out.Subject.FillFromRDNSequence(&in.TBSCertificate.Subject) |
| out.NotBefore = in.TBSCertificate.Validity.NotBefore |
| out.NotAfter = in.TBSCertificate.Validity.NotAfter |
| |
| for _, e := range in.TBSCertificate.Extensions { |
| 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 |
| _, err := asn1.Unmarshal(e.Value, &usageBits) |
| |
| if err == nil { |
| var usage int |
| for i := 0; i < 9; i++ { |
| if usageBits.At(i) != 0 { |
| usage |= 1 << uint(i) |
| } |
| } |
| out.KeyUsage = KeyUsage(usage) |
| continue |
| } |
| case 19: |
| // RFC 5280, 4.2.1.9 |
| var constraints basicConstraints |
| _, err := asn1.Unmarshal(e.Value, &constraints) |
| |
| if err == nil { |
| out.BasicConstraintsValid = true |
| out.IsCA = constraints.IsCA |
| out.MaxPathLen = constraints.MaxPathLen |
| continue |
| } |
| case 17: |
| // 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 |
| _, err := asn1.Unmarshal(e.Value, &seq) |
| if err != nil { |
| return nil, err |
| } |
| if !seq.IsCompound || seq.Tag != 16 || seq.Class != 0 { |
| return nil, asn1.StructuralError{"bad SAN sequence"} |
| } |
| |
| parsedName := false |
| |
| rest := seq.Bytes |
| for len(rest) > 0 { |
| var v asn1.RawValue |
| rest, err = asn1.Unmarshal(rest, &v) |
| if err != nil { |
| return nil, err |
| } |
| switch v.Tag { |
| case 1: |
| out.EmailAddresses = append(out.EmailAddresses, string(v.Bytes)) |
| parsedName = true |
| case 2: |
| out.DNSNames = append(out.DNSNames, string(v.Bytes)) |
| parsedName = true |
| } |
| } |
| |
| if parsedName { |
| continue |
| } |
| // If we didn't parse any of the names then we |
| // fall through to the critical check below. |
| |
| case 30: |
| // 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) |
| |
| var constraints nameConstraints |
| _, err := asn1.Unmarshal(e.Value, &constraints) |
| if err != nil { |
| return nil, err |
| } |
| |
| if len(constraints.Excluded) > 0 && e.Critical { |
| return out, UnhandledCriticalExtension{} |
| } |
| |
| for _, subtree := range constraints.Permitted { |
| if subtree.Min > 0 || subtree.Max > 0 || len(subtree.Name) == 0 { |
| if e.Critical { |
| return out, UnhandledCriticalExtension{} |
| } |
| continue |
| } |
| out.PermittedDNSDomains = append(out.PermittedDNSDomains, subtree.Name) |
| } |
| continue |
| |
| case 35: |
| // RFC 5280, 4.2.1.1 |
| var a authKeyId |
| _, err = asn1.Unmarshal(e.Value, &a) |
| if err != nil { |
| return nil, err |
| } |
| out.AuthorityKeyId = a.Id |
| continue |
| |
| 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 |
| _, err = asn1.Unmarshal(e.Value, &keyUsage) |
| if err != nil { |
| return nil, err |
| } |
| |
| for _, u := range keyUsage { |
| switch { |
| case u.Equal(oidExtKeyUsageAny): |
| out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageAny) |
| case u.Equal(oidExtKeyUsageServerAuth): |
| out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageServerAuth) |
| case u.Equal(oidExtKeyUsageClientAuth): |
| out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageClientAuth) |
| case u.Equal(oidExtKeyUsageCodeSigning): |
| out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageCodeSigning) |
| case u.Equal(oidExtKeyUsageEmailProtection): |
| out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageEmailProtection) |
| case u.Equal(oidExtKeyUsageTimeStamping): |
| out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageTimeStamping) |
| case u.Equal(oidExtKeyUsageOCSPSigning): |
| out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageOCSPSigning) |
| default: |
| out.UnknownExtKeyUsage = append(out.UnknownExtKeyUsage, u) |
| } |
| } |
| |
| continue |
| |
| case 14: |
| // RFC 5280, 4.2.1.2 |
| var keyid []byte |
| _, err = asn1.Unmarshal(e.Value, &keyid) |
| if err != nil { |
| return nil, err |
| } |
| out.SubjectKeyId = keyid |
| continue |
| |
| case 32: |
| // RFC 5280 4.2.1.4: Certificate Policies |
| var policies []policyInformation |
| if _, err = asn1.Unmarshal(e.Value, &policies); err != nil { |
| return nil, err |
| } |
| out.PolicyIdentifiers = make([]asn1.ObjectIdentifier, len(policies)) |
| for i, policy := range policies { |
| out.PolicyIdentifiers[i] = policy.Policy |
| } |
| } |
| } |
| |
| if e.Critical { |
| return out, UnhandledCriticalExtension{} |
| } |
| } |
| |
| return out, nil |
| } |
| |
| // ParseCertificate parses a single certificate from the given ASN.1 DER data. |
| func ParseCertificate(asn1Data []byte) (*Certificate, os.Error) { |
| var cert certificate |
| rest, err := asn1.Unmarshal(asn1Data, &cert) |
| if err != nil { |
| return nil, err |
| } |
| if len(rest) > 0 { |
| return nil, asn1.SyntaxError{"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, os.Error) { |
| var v []*certificate |
| |
| for len(asn1Data) > 0 { |
| cert := new(certificate) |
| var err os.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 |
| } |
| |
| var ( |
| oidExtensionSubjectKeyId = []int{2, 5, 29, 14} |
| oidExtensionKeyUsage = []int{2, 5, 29, 15} |
| 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} |
| ) |
| |
| func buildExtensions(template *Certificate) (ret []pkix.Extension, err os.Error) { |
| ret = make([]pkix.Extension, 7 /* maximum number of elements. */ ) |
| n := 0 |
| |
| if template.KeyUsage != 0 { |
| 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 |
| } |
| |
| ret[n].Value, err = asn1.Marshal(asn1.BitString{Bytes: a[0:l], BitLength: l * 8}) |
| if err != nil { |
| return |
| } |
| n++ |
| } |
| |
| if template.BasicConstraintsValid { |
| ret[n].Id = oidExtensionBasicConstraints |
| ret[n].Value, err = asn1.Marshal(basicConstraints{template.IsCA, template.MaxPathLen}) |
| ret[n].Critical = true |
| if err != nil { |
| return |
| } |
| n++ |
| } |
| |
| if len(template.SubjectKeyId) > 0 { |
| ret[n].Id = oidExtensionSubjectKeyId |
| ret[n].Value, err = asn1.Marshal(template.SubjectKeyId) |
| if err != nil { |
| return |
| } |
| n++ |
| } |
| |
| if len(template.AuthorityKeyId) > 0 { |
| ret[n].Id = oidExtensionAuthorityKeyId |
| ret[n].Value, err = asn1.Marshal(authKeyId{template.AuthorityKeyId}) |
| if err != nil { |
| return |
| } |
| n++ |
| } |
| |
| if len(template.DNSNames) > 0 { |
| ret[n].Id = oidExtensionSubjectAltName |
| rawValues := make([]asn1.RawValue, len(template.DNSNames)) |
| for i, name := range template.DNSNames { |
| rawValues[i] = asn1.RawValue{Tag: 2, Class: 2, Bytes: []byte(name)} |
| } |
| ret[n].Value, err = asn1.Marshal(rawValues) |
| if err != nil { |
| return |
| } |
| n++ |
| } |
| |
| if len(template.PolicyIdentifiers) > 0 { |
| 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 { |
| ret[n].Id = oidExtensionNameConstraints |
| ret[n].Critical = template.PermittedDNSDomainsCritical |
| |
| var out nameConstraints |
| out.Permitted = make([]generalSubtree, len(template.PermittedDNSDomains)) |
| for i, permitted := range template.PermittedDNSDomains { |
| out.Permitted[i] = generalSubtree{Name: permitted} |
| } |
| ret[n].Value, err = asn1.Marshal(out) |
| 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 ret[0:n], nil |
| } |
| |
| var ( |
| oidSHA1WithRSA = []int{1, 2, 840, 113549, 1, 1, 5} |
| oidRSA = []int{1, 2, 840, 113549, 1, 1, 1} |
| ) |
| |
| // CreateSelfSignedCertificate creates a new certificate based on |
| // a template. The following members of template are used: SerialNumber, |
| // Subject, NotBefore, NotAfter, KeyUsage, BasicConstraintsValid, IsCA, |
| // MaxPathLen, SubjectKeyId, DNSNames, PermittedDNSDomainsCritical, |
| // PermittedDNSDomains. |
| // |
| // 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. |
| func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.PublicKey, priv *rsa.PrivateKey) (cert []byte, err os.Error) { |
| asn1PublicKey, err := asn1.Marshal(rsaPublicKey{ |
| N: pub.N, |
| E: pub.E, |
| }) |
| if err != nil { |
| return |
| } |
| |
| if len(parent.SubjectKeyId) > 0 { |
| template.AuthorityKeyId = parent.SubjectKeyId |
| } |
| |
| extensions, err := buildExtensions(template) |
| if err != nil { |
| return |
| } |
| |
| encodedPublicKey := asn1.BitString{BitLength: len(asn1PublicKey) * 8, Bytes: asn1PublicKey} |
| c := tbsCertificate{ |
| Version: 2, |
| SerialNumber: template.SerialNumber, |
| SignatureAlgorithm: pkix.AlgorithmIdentifier{Algorithm: oidSHA1WithRSA}, |
| Issuer: parent.Subject.ToRDNSequence(), |
| Validity: validity{template.NotBefore, template.NotAfter}, |
| Subject: template.Subject.ToRDNSequence(), |
| PublicKey: publicKeyInfo{nil, pkix.AlgorithmIdentifier{Algorithm: oidRSA}, encodedPublicKey}, |
| Extensions: extensions, |
| } |
| |
| tbsCertContents, err := asn1.Marshal(c) |
| if err != nil { |
| return |
| } |
| |
| c.Raw = tbsCertContents |
| |
| h := sha1.New() |
| h.Write(tbsCertContents) |
| digest := h.Sum() |
| |
| signature, err := rsa.SignPKCS1v15(rand, priv, crypto.SHA1, digest) |
| if err != nil { |
| return |
| } |
| |
| cert, err = asn1.Marshal(certificate{ |
| nil, |
| c, |
| pkix.AlgorithmIdentifier{Algorithm: oidSHA1WithRSA}, |
| asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, |
| }) |
| return |
| } |
| |
| // 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) (certList *pkix.CertificateList, err os.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) (certList *pkix.CertificateList, err os.Error) { |
| certList = new(pkix.CertificateList) |
| _, err = asn1.Unmarshal(derBytes, certList) |
| if err != nil { |
| certList = nil |
| } |
| return |
| } |
| |
| // 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 *rsa.PrivateKey, revokedCerts []pkix.RevokedCertificate, now, expiry *time.Time) (crlBytes []byte, err os.Error) { |
| tbsCertList := pkix.TBSCertificateList{ |
| Version: 2, |
| Signature: pkix.AlgorithmIdentifier{ |
| Algorithm: oidSignatureSHA1WithRSA, |
| }, |
| Issuer: c.Subject.ToRDNSequence(), |
| ThisUpdate: now, |
| NextUpdate: expiry, |
| RevokedCertificates: revokedCerts, |
| } |
| |
| tbsCertListContents, err := asn1.Marshal(tbsCertList) |
| if err != nil { |
| return |
| } |
| |
| h := sha1.New() |
| h.Write(tbsCertListContents) |
| digest := h.Sum() |
| |
| signature, err := rsa.SignPKCS1v15(rand, priv, crypto.SHA1, digest) |
| if err != nil { |
| return |
| } |
| |
| return asn1.Marshal(pkix.CertificateList{ |
| TBSCertList: tbsCertList, |
| SignatureAlgorithm: pkix.AlgorithmIdentifier{ |
| Algorithm: oidSignatureSHA1WithRSA, |
| }, |
| SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, |
| }) |
| } |