// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// NOTE: PACKAGE UNDER CONSTRUCTION.
-//
// This package parses X.509-encoded keys and certificates.
package x509
import (
"asn1";
"big";
+ "container/vector";
"crypto/rsa";
+ "crypto/sha1";
+ "hash";
"os";
+ "strings";
+ "time";
)
// pkcs1PrivateKey is a structure which mirrors the PKCS#1 ASN.1 for an RSA private key.
// 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;
- _, err = asn1.Unmarshal(&priv, der);
+ rest, err := asn1.Unmarshal(&priv, der);
+ if len(rest) > 0 {
+ err = asn1.SyntaxError{"trailing data"};
+ return;
+ }
if err != nil {
return
}
}
return;
}
+
+// These structures reflect the ASN.1 structure of X.509 certificates.:
+
+type certificate struct {
+ TBSCertificate tbsCertificate;
+ SignatureAlgorithm algorithmIdentifier;
+ SignatureValue asn1.BitString;
+}
+
+type tbsCertificate struct {
+ Raw asn1.RawContents;
+ Version int "optional,explicit,default:1,tag:0";
+ SerialNumber asn1.RawValue;
+ SignatureAlgorithm algorithmIdentifier;
+ Issuer rdnSequence;
+ Validity validity;
+ Subject rdnSequence;
+ PublicKey publicKeyInfo;
+ UniqueId asn1.BitString "optional,explicit,tag:1";
+ SubjectUniqueId asn1.BitString "optional,explicit,tag:2";
+ Extensions []extension "optional,explicit,tag:3";
+}
+
+type algorithmIdentifier struct {
+ Algorithm asn1.ObjectIdentifier;
+}
+
+type rdnSequence []relativeDistinguishedName
+
+type relativeDistinguishedName []attributeTypeAndValue
+
+type attributeTypeAndValue struct {
+ Type asn1.ObjectIdentifier;
+ Value interface{};
+}
+
+type validity struct {
+ NotBefore, NotAfter *time.Time;
+}
+
+type publicKeyInfo struct {
+ Algorithm algorithmIdentifier;
+ PublicKey asn1.BitString;
+}
+
+type extension struct {
+ Id asn1.ObjectIdentifier;
+ Critical bool "optional";
+ Value []byte;
+}
+
+// RFC 5280, 4.2.1.1
+type authKeyId struct {
+ Id []byte "optional,tag:0";
+}
+
+type SignatureAlgorithm int
+
+const (
+ UnknownSignatureAlgorithm SignatureAlgorithm = iota;
+ MD2WithRSA;
+ MD5WithRSA;
+ SHA1WithRSA;
+ SHA256WithRSA;
+ SHA384WithRSA;
+ SHA512WithRSA;
+)
+
+type PublicKeyAlgorithm int
+
+const (
+ UnknownPublicKeyAlgorithm PublicKeyAlgorithm = iota;
+ RSA;
+)
+
+// Name represents an X.509 distinguished name. This only includes the common
+// elements of a DN. Additional elements in the name are ignored.
+type Name struct {
+ Country, Organization, OrganizationalUnit string;
+ CommonName, SerialNumber, Locality string;
+ Province, StreetAddress, PostalCode string;
+}
+
+func (n *Name) fillFromRDNSequence(rdns *rdnSequence) {
+ for _, rdn := range *rdns {
+ if len(rdn) == 0 {
+ continue
+ }
+ atv := rdn[0];
+ value, ok := atv.Value.(string);
+ if !ok {
+ continue
+ }
+
+ t := atv.Type;
+ if len(t) == 4 && t[0] == 2 && t[1] == 5 && t[2] == 4 {
+ switch t[3] {
+ case 3:
+ n.CommonName = value
+ case 5:
+ n.SerialNumber = value
+ case 6:
+ n.Country = value
+ case 7:
+ n.Locality = value
+ case 8:
+ n.Province = value
+ case 9:
+ n.StreetAddress = value
+ case 10:
+ n.Organization = value
+ case 11:
+ n.OrganizationalUnit = value
+ case 17:
+ n.PostalCode = value
+ }
+ }
+ }
+}
+
+func getSignatureAlgorithmFromOID(oid []int) SignatureAlgorithm {
+ if len(oid) == 7 && oid[0] == 1 && oid[1] == 2 && oid[2] == 840 &&
+ oid[3] == 113549 && oid[4] == 1 && oid[5] == 1 {
+ switch oid[6] {
+ case 2:
+ return MD2WithRSA
+ case 4:
+ return MD5WithRSA
+ case 5:
+ return SHA1WithRSA
+ case 11:
+ return SHA256WithRSA
+ case 12:
+ return SHA384WithRSA
+ case 13:
+ return SHA512WithRSA
+ }
+ }
+
+ return UnknownSignatureAlgorithm;
+}
+
+func getPublicKeyAlgorithmFromOID(oid []int) PublicKeyAlgorithm {
+ if len(oid) == 7 && oid[0] == 1 && oid[1] == 2 && oid[2] == 840 &&
+ oid[3] == 113549 && oid[4] == 1 && oid[5] == 1 {
+ switch oid[6] {
+ case 1:
+ return RSA
+ }
+ }
+
+ 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;
+)
+
+// A Certificate represents an X.509 certificate.
+type Certificate struct {
+ Raw []byte; // Raw ASN.1 DER contents.
+ Signature []byte;
+ SignatureAlgorithm SignatureAlgorithm;
+
+ PublicKeyAlgorithm PublicKeyAlgorithm;
+ PublicKey interface{};
+
+ Version int;
+ SerialNumber []byte;
+ Issuer Name;
+ Subject Name;
+ NotBefore, NotAfter *time.Time; // Validity bounds.
+ KeyUsage KeyUsage;
+
+ 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;
+}
+
+// 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"
+}
+
+// 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.
+
+ var h hash.Hash;
+ var hashType rsa.PKCS1v15Hash;
+
+ switch c.SignatureAlgorithm {
+ case SHA1WithRSA:
+ h = sha1.New();
+ hashType = rsa.HashSHA1;
+ default:
+ return UnsupportedAlgorithmError{}
+ }
+
+ pub, ok := parent.PublicKey.(*rsa.PublicKey);
+ if !ok {
+ return UnsupportedAlgorithmError{}
+ }
+
+ h.Write(c.Raw);
+ digest := h.Sum();
+
+ return rsa.VerifyPKCS1v15(pub, hashType, digest, c.Signature);
+}
+
+func matchHostnames(pattern, host string) bool {
+ if len(pattern) == 0 || len(host) == 0 {
+ return false
+ }
+
+ patternParts := strings.Split(pattern, ".", 0);
+ hostParts := strings.Split(host, ".", 0);
+
+ if len(patternParts) != len(hostParts) {
+ return false
+ }
+
+ for i, patternPart := range patternParts {
+ if patternPart == "*" {
+ continue
+ }
+ if patternPart != hostParts[i] {
+ return false
+ }
+ }
+
+ return true;
+}
+
+// IsValidForHost returns true iff c is a valid certificate for the given host.
+func (c *Certificate) IsValidForHost(h string) bool {
+ if len(c.DNSNames) > 0 {
+ for _, match := range c.DNSNames {
+ if matchHostnames(match, h) {
+ return true
+ }
+ }
+ // If Subject Alt Name is given, we ignore the common name.
+ return false;
+ }
+
+ return matchHostnames(c.Subject.CommonName, h);
+}
+
+type UnhandledCriticalExtension struct{}
+
+func (h UnhandledCriticalExtension) String() string {
+ return "unhandled critical extension"
+}
+
+type basicConstraints struct {
+ IsCA bool "optional";
+ MaxPathLen int "optional";
+}
+
+type rsaPublicKey struct {
+ N asn1.RawValue;
+ E int;
+}
+
+func parsePublicKey(algo PublicKeyAlgorithm, asn1Data []byte) (interface{}, os.Error) {
+ switch algo {
+ case RSA:
+ p := new(rsaPublicKey);
+ _, err := asn1.Unmarshal(p, asn1Data);
+ if err != nil {
+ return nil, err
+ }
+
+ if !rawValueIsInteger(&p.N) {
+ return nil, asn1.StructuralError{"tags don't match"}
+ }
+
+ pub := &rsa.PublicKey{
+ E: p.E,
+ N: new(big.Int).SetBytes(p.N.Bytes),
+ };
+ return pub, nil;
+ default:
+ return nil, nil
+ }
+
+ panic("unreachable");
+}
+
+func appendString(in []string, v string) (out []string) {
+ if cap(in)-len(in) < 1 {
+ out = make([]string, len(in)+1, len(in)*2+1);
+ for i, v := range in {
+ out[i] = v
+ }
+ } else {
+ out = in[0 : len(in)+1]
+ }
+ out[len(in)] = v;
+ return out;
+}
+
+func parseCertificate(in *certificate) (*Certificate, os.Error) {
+ out := new(Certificate);
+ out.Raw = in.TBSCertificate.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.PublicKey.RightAlign());
+ if err != nil {
+ return nil, err
+ }
+
+ out.Version = in.TBSCertificate.Version;
+ out.SerialNumber = in.TBSCertificate.SerialNumber.Bytes;
+ 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(&usageBits, e.Value);
+
+ 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 constriants basicConstraints;
+ _, err := asn1.Unmarshal(&constriants, e.Value);
+
+ if err == nil {
+ out.BasicConstraintsValid = true;
+ out.IsCA = constriants.IsCA;
+ out.MaxPathLen = constriants.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(&seq, e.Value);
+ 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(&v, rest);
+ if err != nil {
+ return nil, err
+ }
+ switch v.Tag {
+ case 1:
+ out.EmailAddresses = appendString(out.EmailAddresses, string(v.Bytes));
+ parsedName = true;
+ case 2:
+ out.DNSNames = appendString(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 35:
+ // RFC 5280, 4.2.1.1
+ var a authKeyId;
+ _, err = asn1.Unmarshal(&a, e.Value);
+ if err != nil {
+ return nil, err
+ }
+ out.AuthorityKeyId = a.Id;
+ continue;
+
+ case 14:
+ // RFC 5280, 4.2.1.2
+ out.SubjectKeyId = e.Value;
+ continue;
+ }
+ }
+
+ 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(&cert, asn1Data);
+ 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) {
+ v := vector.New(0);
+
+ for len(asn1Data) > 0 {
+ cert := new(certificate);
+ var err os.Error;
+ asn1Data, err = asn1.Unmarshal(cert, asn1Data);
+ if err != nil {
+ return nil, err
+ }
+ v.Push(cert);
+ }
+
+ ret := make([]*Certificate, v.Len());
+ for i := 0; i < v.Len(); i++ {
+ cert, err := parseCertificate(v.At(i).(*certificate));
+ if err != nil {
+ return nil, err
+ }
+ ret[i] = cert;
+ }
+
+ return ret, nil;
+}
import (
"big";
"crypto/rsa";
+ "encoding/hex";
"encoding/pem";
"reflect";
"strings";
P: bigFromString("98920366548084643601728869055592650835572950932266967461790948584315647051443"),
Q: bigFromString("94560208308847015747498523884063394671606671904944666360068158221458669711639"),
}
+
+type matchHostnamesTest struct {
+ pattern, host string;
+ ok bool;
+}
+
+var matchHostnamesTests = []matchHostnamesTest{
+ matchHostnamesTest{"a.b.c", "a.b.c", true},
+ matchHostnamesTest{"a.b.c", "b.b.c", false},
+ matchHostnamesTest{"", "b.b.c", false},
+ matchHostnamesTest{"a.b.c", "", false},
+ matchHostnamesTest{"example.com", "example.com", true},
+ matchHostnamesTest{"example.com", "www.example.com", false},
+ matchHostnamesTest{"*.example.com", "www.example.com", true},
+ matchHostnamesTest{"*.example.com", "xyz.www.example.com", false},
+ matchHostnamesTest{"*.*.example.com", "xyz.www.example.com", true},
+ matchHostnamesTest{"*.www.*.com", "xyz.www.example.com", true},
+}
+
+func TestMatchHostnames(t *testing.T) {
+ for i, test := range matchHostnamesTests {
+ r := matchHostnames(test.pattern, test.host);
+ if r != test.ok {
+ t.Errorf("#%d mismatch got: %t want: %t", i, r, test.ok)
+ }
+ }
+}
+
+func TestCertificateParse(t *testing.T) {
+ s, _ := hex.DecodeString(certBytes);
+ certs, err := ParseCertificates(s);
+ if err != nil {
+ t.Error(err)
+ }
+ if len(certs) != 2 {
+ t.Errorf("Wrong number of certs: got %d want 2", len(certs));
+ return;
+ }
+
+ err = certs[0].CheckSignatureFrom(certs[1]);
+ if err != nil {
+ t.Error(err)
+ }
+
+ if !certs[0].IsValidForHost("mail.google.com") {
+ t.Errorf("cert not valid for host")
+ }
+}
+
+var certBytes = "308203223082028ba00302010202106edf0d9499fd4533dd1297fc42a93be1300d06092a864886"
+ "f70d0101050500304c310b3009060355040613025a4131253023060355040a131c546861777465"
+ "20436f6e73756c74696e67202850747929204c74642e311630140603550403130d546861777465"
+ "20534743204341301e170d3039303332353136343932395a170d3130303332353136343932395a"
+ "3069310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630"
+ "140603550407130d4d6f756e7461696e205669657731133011060355040a130a476f6f676c6520"
+ "496e63311830160603550403130f6d61696c2e676f6f676c652e636f6d30819f300d06092a8648"
+ "86f70d010101050003818d0030818902818100c5d6f892fccaf5614b064149e80a2c9581a218ef"
+ "41ec35bd7a58125ae76f9ea54ddc893abbeb029f6b73616bf0ffd868791fba7af9c4aebf3706ba"
+ "3eeaeed27435b4ddcfb157c05f351d66aa87fee0de072d66d773affbd36ab78bef090e0cc861a9"
+ "03ac90dd98b51c9c41566c017f0beec3bff391051ffba0f5cc6850ad2a590203010001a381e730"
+ "81e430280603551d250421301f06082b0601050507030106082b06010505070302060960864801"
+ "86f842040130360603551d1f042f302d302ba029a0278625687474703a2f2f63726c2e74686177"
+ "74652e636f6d2f54686177746553474343412e63726c307206082b060105050701010466306430"
+ "2206082b060105050730018616687474703a2f2f6f6373702e7468617774652e636f6d303e0608"
+ "2b060105050730028632687474703a2f2f7777772e7468617774652e636f6d2f7265706f736974"
+ "6f72792f5468617774655f5347435f43412e637274300c0603551d130101ff04023000300d0609"
+ "2a864886f70d01010505000381810062f1f3050ebc105e497c7aedf87e24d2f4a986bb3b837bd1"
+ "9b91ebcad98b065992f6bd2b49b7d6d3cb2e427a99d606c7b1d46352527fac39e6a8b6726de5bf"
+ "70212a52cba07634a5e332011bd1868e78eb5e3c93cf03072276786f207494feaa0ed9d53b2110"
+ "a76571f90209cdae884385c882587030ee15f33d761e2e45a6bc308203233082028ca003020102"
+ "020430000002300d06092a864886f70d0101050500305f310b3009060355040613025553311730"
+ "15060355040a130e566572695369676e2c20496e632e31373035060355040b132e436c61737320"
+ "33205075626c6963205072696d6172792043657274696669636174696f6e20417574686f726974"
+ "79301e170d3034303531333030303030305a170d3134303531323233353935395a304c310b3009"
+ "060355040613025a4131253023060355040a131c54686177746520436f6e73756c74696e672028"
+ "50747929204c74642e311630140603550403130d5468617774652053474320434130819f300d06"
+ "092a864886f70d010101050003818d0030818902818100d4d367d08d157faecd31fe7d1d91a13f"
+ "0b713cacccc864fb63fc324b0794bd6f80ba2fe10493c033fc093323e90b742b71c403c6d2cde2"
+ "2ff50963cdff48a500bfe0e7f388b72d32de9836e60aad007bc4644a3b847503f270927d0e62f5"
+ "21ab693684317590f8bfc76c881b06957cc9e5a8de75a12c7a68dfd5ca1c875860190203010001"
+ "a381fe3081fb30120603551d130101ff040830060101ff020100300b0603551d0f040403020106"
+ "301106096086480186f842010104040302010630280603551d110421301fa41d301b3119301706"
+ "035504031310507269766174654c6162656c332d313530310603551d1f042a30283026a024a022"
+ "8620687474703a2f2f63726c2e766572697369676e2e636f6d2f706361332e63726c303206082b"
+ "0601050507010104263024302206082b060105050730018616687474703a2f2f6f6373702e7468"
+ "617774652e636f6d30340603551d25042d302b06082b0601050507030106082b06010505070302"
+ "06096086480186f8420401060a6086480186f845010801300d06092a864886f70d010105050003"
+ "81810055ac63eadea1ddd2905f9f0bce76be13518f93d9052bc81b774bad6950a1eededcfddb07"
+ "e9e83994dcab72792f06bfab8170c4a8edea5334edef1e53d906c7562bd15cf4d18a8eb42bb137"
+ "9048084225c53e8acb7feb6f04d16dc574a2f7a27c7b603c77cd0ece48027f012fb69b37e02a2a"
+ "36dcd585d6ace53f546f961e05af"