URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [crypto/] [x509/] [x509.go] - Rev 747
Compare with Previous | Blame | View Log
// 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 x509import ("bytes""crypto""crypto/dsa""crypto/rsa""crypto/sha1""crypto/x509/pkix""encoding/asn1""encoding/pem""errors""io""math/big""time")// pkixPublicKey reflects a PKIX public key structure. See SubjectPublicKeyInfo// in RFC 3280.type pkixPublicKey struct {Algo pkix.AlgorithmIdentifierBitString asn1.BitString}// ParsePKIXPublicKey parses a DER encoded public key. These values are// typically found in PEM blocks with "BEGIN PUBLIC KEY".func ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err error) {var pki publicKeyInfoif _, err = asn1.Unmarshal(derBytes, &pki); err != nil {return}algo := getPublicKeyAlgorithmFromOID(pki.Algorithm.Algorithm)if algo == UnknownPublicKeyAlgorithm {return nil, errors.New("ParsePKIXPublicKey: unknown public key algorithm")}return parsePublicKey(algo, &pki)}// MarshalPKIXPublicKey serialises a public key to DER-encoded PKIX format.func MarshalPKIXPublicKey(pub interface{}) ([]byte, error) {var pubBytes []byteswitch pub := pub.(type) {case *rsa.PublicKey:pubBytes, _ = asn1.Marshal(rsaPublicKey{N: pub.N,E: pub.E,})default:return nil, errors.New("MarshalPKIXPublicKey: unknown public key type")}pkix := pkixPublicKey{Algo: pkix.AlgorithmIdentifier{Algorithm: []int{1, 2, 840, 113549, 1, 1, 1},// This is a NULL parameters value which is technically// superfluous, but most other code includes it and, by// doing this, we match their public key hashes.Parameters: asn1.RawValue{Tag: 5,},},BitString: asn1.BitString{Bytes: pubBytes,BitLength: 8 * len(pubBytes),},}ret, _ := asn1.Marshal(pkix)return ret, nil}// These structures reflect the ASN.1 structure of X.509 certificates.:type certificate struct {Raw asn1.RawContentTBSCertificate tbsCertificateSignatureAlgorithm pkix.AlgorithmIdentifierSignatureValue asn1.BitString}type tbsCertificate struct {Raw asn1.RawContentVersion int `asn1:"optional,explicit,default:1,tag:0"`SerialNumber *big.IntSignatureAlgorithm pkix.AlgorithmIdentifierIssuer asn1.RawValueValidity validitySubject asn1.RawValuePublicKey publicKeyInfoUniqueId 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.RawContentAlgorithm pkix.AlgorithmIdentifierPublicKey asn1.BitString}// RFC 5280, 4.2.1.1type authKeyId struct {Id []byte `asn1:"optional,tag:0"`}type SignatureAlgorithm intconst (UnknownSignatureAlgorithm SignatureAlgorithm = iotaMD2WithRSAMD5WithRSASHA1WithRSASHA256WithRSASHA384WithRSASHA512WithRSADSAWithSHA1DSAWithSHA256)type PublicKeyAlgorithm intconst (UnknownPublicKeyAlgorithm PublicKeyAlgorithm = iotaRSADSA)// 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 MD2WithRSAcase oid.Equal(oidSignatureMD5WithRSA):return MD5WithRSAcase oid.Equal(oidSignatureSHA1WithRSA):return SHA1WithRSAcase oid.Equal(oidSignatureSHA256WithRSA):return SHA256WithRSAcase oid.Equal(oidSignatureSHA384WithRSA):return SHA384WithRSAcase oid.Equal(oidSignatureSHA512WithRSA):return SHA512WithRSAcase oid.Equal(oidSignatureDSAWithSHA1):return DSAWithSHA1case 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 RSAcase 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 intconst (KeyUsageDigitalSignature KeyUsage = 1 << iotaKeyUsageContentCommitmentKeyUsageKeyEnciphermentKeyUsageDataEnciphermentKeyUsageKeyAgreementKeyUsageCertSignKeyUsageCRLSignKeyUsageEncipherOnlyKeyUsageDecipherOnly)// 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 intconst (ExtKeyUsageAny ExtKeyUsage = iotaExtKeyUsageServerAuthExtKeyUsageClientAuthExtKeyUsageCodeSigningExtKeyUsageEmailProtectionExtKeyUsageTimeStampingExtKeyUsageOCSPSigning)// 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 SubjectRawIssuer []byte // DER encoded IssuerSignature []byteSignatureAlgorithm SignatureAlgorithmPublicKeyAlgorithm PublicKeyAlgorithmPublicKey interface{}Version intSerialNumber *big.IntIssuer pkix.NameSubject pkix.NameNotBefore, NotAfter time.Time // Validity bounds.KeyUsage KeyUsageExtKeyUsage []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 boolMaxPathLen intSubjectKeyId []byteAuthorityKeyId []byte// Subject Alternate Name valuesDNSNames []stringEmailAddresses []string// Name constraintsPermittedDNSDomainsCritical bool // if true then the name constraints are marked critical.PermittedDNSDomains []stringPolicyIdentifiers []asn1.ObjectIdentifier}// UnsupportedAlgorithmError results from attempting to perform an operation// that involves algorithms that are not currently implemented.type UnsupportedAlgorithmError struct{}func (UnsupportedAlgorithmError) Error() 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) Error() 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 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 error) {var hashType crypto.Hashswitch algo {case SHA1WithRSA, DSAWithSHA1:hashType = crypto.SHA1case SHA256WithRSA, DSAWithSHA256:hashType = crypto.SHA256case SHA384WithRSA:hashType = crypto.SHA384case SHA512WithRSA:hashType = crypto.SHA512default:return UnsupportedAlgorithmError{}}h := hashType.New()if h == nil {return UnsupportedAlgorithmError{}}h.Write(signed)digest := h.Sum(nil)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 errors.New("DSA signature contained zero or negative values")}if !dsa.Verify(pub, digest, dsaSig.R, dsaSig.S) {return errors.New("DSA verification failure")}return}return UnsupportedAlgorithmError{}}// CheckCRLSignature checks that the signature in crl is from c.func (c *Certificate) CheckCRLSignature(crl *pkix.CertificateList) (err error) {algo := getSignatureAlgorithmFromOID(crl.SignatureAlgorithm.Algorithm)return c.CheckSignature(algo, crl.TBSCertList.Raw, crl.SignatureValue.RightAlign())}type UnhandledCriticalExtension struct{}func (h UnhandledCriticalExtension) Error() string {return "unhandled critical extension"}type basicConstraints struct {IsCA bool `asn1:"optional"`MaxPathLen int `asn1:"optional"`}// RFC 5280 4.2.1.4type policyInformation struct {Policy asn1.ObjectIdentifier// policyQualifiers omitted}// RFC 5280, 4.2.1.10type 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{}, 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, nilcase DSA:var p *big.Int_, err := asn1.Unmarshal(asn1Data, &p)if err != nil {return nil, err}paramsData := keyData.Algorithm.Parameters.FullBytesparams := 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, errors.New("zero or negative DSA parameter")}pub := &dsa.PublicKey{Parameters: dsa.Parameters{P: params.P,Q: params.Q,G: params.G,},Y: p,}return pub, nildefault:return nil, nil}panic("unreachable")}func parseCertificate(in *certificate) (*Certificate, error) {out := new(Certificate)out.Raw = in.Rawout.RawTBSCertificate = in.TBSCertificate.Rawout.RawSubjectPublicKeyInfo = in.TBSCertificate.PublicKey.Rawout.RawSubject = in.TBSCertificate.Subject.FullBytesout.RawIssuer = in.TBSCertificate.Issuer.FullBytesout.Signature = in.SignatureValue.RightAlign()out.SignatureAlgorithm =getSignatureAlgorithmFromOID(in.TBSCertificate.SignatureAlgorithm.Algorithm)out.PublicKeyAlgorithm =getPublicKeyAlgorithmFromOID(in.TBSCertificate.PublicKey.Algorithm.Algorithm)var err errorout.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, &in.TBSCertificate.PublicKey)if err != nil {return nil, err}if in.TBSCertificate.SerialNumber.Sign() < 0 {return nil, errors.New("negative serial number")}out.Version = in.TBSCertificate.Version + 1out.SerialNumber = in.TBSCertificate.SerialNumbervar issuer, subject pkix.RDNSequenceif _, err := asn1.Unmarshal(in.TBSCertificate.Subject.FullBytes, &subject); err != nil {return nil, err}if _, err := asn1.Unmarshal(in.TBSCertificate.Issuer.FullBytes, &issuer); err != nil {return nil, err}out.Issuer.FillFromRDNSequence(&issuer)out.Subject.FillFromRDNSequence(&subject)out.NotBefore = in.TBSCertificate.Validity.NotBeforeout.NotAfter = in.TBSCertificate.Validity.NotAfterfor _, 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.3var usageBits asn1.BitString_, err := asn1.Unmarshal(e.Value, &usageBits)if err == nil {var usage intfor 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.9var constraints basicConstraints_, err := asn1.Unmarshal(e.Value, &constraints)if err == nil {out.BasicConstraintsValid = trueout.IsCA = constraints.IsCAout.MaxPathLen = constraints.MaxPathLencontinue}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{Msg: "bad SAN sequence"}}parsedName := falserest := seq.Bytesfor len(rest) > 0 {var v asn1.RawValuerest, 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 = truecase 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)}continuecase 35:// RFC 5280, 4.2.1.1var a authKeyId_, err = asn1.Unmarshal(e.Value, &a)if err != nil {return nil, err}out.AuthorityKeyId = a.Idcontinuecase 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 IDENTIFIERvar 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)}}continuecase 14:// RFC 5280, 4.2.1.2var keyid []byte_, err = asn1.Unmarshal(e.Value, &keyid)if err != nil {return nil, err}out.SubjectKeyId = keyidcontinuecase 32:// RFC 5280 4.2.1.4: Certificate Policiesvar policies []policyInformationif _, 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, error) {var cert certificaterest, 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 []*certificatefor len(asn1Data) > 0 {cert := new(certificate)var err errorasn1Data, 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<<4b2 := b1>>2&0x33 | b1<<2&0xccb3 := b2>>1&0x55 | b2<<1&0xaareturn 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 error) {ret = make([]pkix.Extension, 7 /* maximum number of elements. */ )n := 0if template.KeyUsage != 0 {ret[n].Id = oidExtensionKeyUsageret[n].Critical = truevar a [2]bytea[0] = reverseBitsInAByte(byte(template.KeyUsage))a[1] = reverseBitsInAByte(byte(template.KeyUsage >> 8))l := 1if 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 = oidExtensionBasicConstraintsret[n].Value, err = asn1.Marshal(basicConstraints{template.IsCA, template.MaxPathLen})ret[n].Critical = trueif err != nil {return}n++}if len(template.SubjectKeyId) > 0 {ret[n].Id = oidExtensionSubjectKeyIdret[n].Value, err = asn1.Marshal(template.SubjectKeyId)if err != nil {return}n++}if len(template.AuthorityKeyId) > 0 {ret[n].Id = oidExtensionAuthorityKeyIdret[n].Value, err = asn1.Marshal(authKeyId{template.AuthorityKeyId})if err != nil {return}n++}if len(template.DNSNames) > 0 {ret[n].Id = oidExtensionSubjectAltNamerawValues := 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 = oidExtensionCertificatePoliciespolicies := 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 = oidExtensionNameConstraintsret[n].Critical = template.PermittedDNSDomainsCriticalvar out nameConstraintsout.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})func subjectBytes(cert *Certificate) ([]byte, error) {if len(cert.RawSubject) > 0 {return cert.RawSubject, nil}return asn1.Marshal(cert.Subject.ToRDNSequence())}// CreateCertificate 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.//// The only supported key type is RSA (*rsa.PublicKey for pub, *rsa.PrivateKey// for priv).func CreateCertificate(rand io.Reader, template, parent *Certificate, pub interface{}, priv interface{}) (cert []byte, err error) {rsaPub, ok := pub.(*rsa.PublicKey)if !ok {return nil, errors.New("x509: non-RSA public keys not supported")}rsaPriv, ok := priv.(*rsa.PrivateKey)if !ok {return nil, errors.New("x509: non-RSA private keys not supported")}asn1PublicKey, err := asn1.Marshal(rsaPublicKey{N: rsaPub.N,E: rsaPub.E,})if err != nil {return}if len(parent.SubjectKeyId) > 0 {template.AuthorityKeyId = parent.SubjectKeyId}extensions, err := buildExtensions(template)if err != nil {return}asn1Issuer, err := subjectBytes(parent)if err != nil {return}asn1Subject, err := subjectBytes(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: asn1.RawValue{FullBytes: asn1Issuer},Validity: validity{template.NotBefore, template.NotAfter},Subject: asn1.RawValue{FullBytes: asn1Subject},PublicKey: publicKeyInfo{nil, pkix.AlgorithmIdentifier{Algorithm: oidRSA}, encodedPublicKey},Extensions: extensions,}tbsCertContents, err := asn1.Marshal(c)if err != nil {return}c.Raw = tbsCertContentsh := sha1.New()h.Write(tbsCertContents)digest := h.Sum(nil)signature, err := rsa.SignPKCS1v15(rand, rsaPriv, 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 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 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.//// The only supported key type is RSA (*rsa.PrivateKey for priv).func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts []pkix.RevokedCertificate, now, expiry time.Time) (crlBytes []byte, err error) {rsaPriv, ok := priv.(*rsa.PrivateKey)if !ok {return nil, errors.New("x509: non-RSA private keys not supported")}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(nil)signature, err := rsa.SignPKCS1v15(rand, rsaPriv, 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},})}
