Plan 9 from Bell Labs’s /usr/web/sources/contrib/ericvh/go-plan9/src/pkg/crypto/x509/x509.go

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


// 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.

// 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.
type pkcs1PrivateKey struct {
	Version	int;
	N	asn1.RawValue;
	E	int;
	D	asn1.RawValue;
	P	asn1.RawValue;
	Q	asn1.RawValue;
}

// rawValueIsInteger returns true iff the given ASN.1 RawValue is an INTEGER type.
func rawValueIsInteger(raw *asn1.RawValue) bool {
	return raw.Class == 0 && raw.Tag == 2 && raw.IsCompound == false
}

// 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(&priv, der);
	if len(rest) > 0 {
		err = asn1.SyntaxError{"trailing data"};
		return;
	}
	if err != nil {
		return
	}

	if !rawValueIsInteger(&priv.N) ||
		!rawValueIsInteger(&priv.D) ||
		!rawValueIsInteger(&priv.P) ||
		!rawValueIsInteger(&priv.Q) {
		err = asn1.StructuralError{"tags don't match"};
		return;
	}

	key = &rsa.PrivateKey{
		PublicKey: rsa.PublicKey{
			E: priv.E,
			N: new(big.Int).SetBytes(priv.N.Bytes),
		},
		D: new(big.Int).SetBytes(priv.D.Bytes),
		P: new(big.Int).SetBytes(priv.P.Bytes),
		Q: new(big.Int).SetBytes(priv.Q.Bytes),
	};

	err = key.Validate();
	if err != nil {
		return nil, err
	}
	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.RawContent;
	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 := new(vector.Vector);

	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;
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.