mirror of
https://github.com/golang/go
synced 2024-11-21 22:54:40 -07:00
crypto: reorg, cleanup and add function for generating CRLs.
This change moves a number of common PKIX structures into crypto/x509/pkix, from where x509, and ocsp can reference them, saving duplication. It also removes x509/crl and merges it into x509 and x509/pkix. x509 is changed to take advantage of the big.Int support that now exists in asn1. Because of this, the public/private key pair in http/httptest/server.go had to be updated because it was serialised with an old version of the code that didn't zero pad ASN.1 INTEGERs. R=bradfitz, rsc CC=golang-dev https://golang.org/cl/4532115
This commit is contained in:
parent
548e3d0342
commit
c281ddf1eb
@ -59,7 +59,7 @@ DIRS=\
|
||||
crypto/tls\
|
||||
crypto/twofish\
|
||||
crypto/x509\
|
||||
crypto/x509/crl\
|
||||
crypto/x509/pkix\
|
||||
crypto/xtea\
|
||||
debug/dwarf\
|
||||
debug/macho\
|
||||
@ -184,6 +184,7 @@ endif
|
||||
NOTEST+=\
|
||||
crypto\
|
||||
crypto/openpgp/error\
|
||||
crypto/x509/pkix\
|
||||
debug/proc\
|
||||
exp/gui\
|
||||
exp/gui/x11\
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"crypto/rsa"
|
||||
_ "crypto/sha1"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
@ -32,21 +33,9 @@ const (
|
||||
ocspUnauthorized = 5
|
||||
)
|
||||
|
||||
type rdnSequence []relativeDistinguishedNameSET
|
||||
|
||||
type relativeDistinguishedNameSET []attributeTypeAndValue
|
||||
|
||||
type attributeTypeAndValue struct {
|
||||
Type asn1.ObjectIdentifier
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
type algorithmIdentifier struct {
|
||||
Algorithm asn1.ObjectIdentifier
|
||||
}
|
||||
|
||||
type certID struct {
|
||||
HashAlgorithm algorithmIdentifier
|
||||
HashAlgorithm pkix.AlgorithmIdentifier
|
||||
NameHash []byte
|
||||
IssuerKeyHash []byte
|
||||
SerialNumber asn1.RawValue
|
||||
@ -64,7 +53,7 @@ type responseBytes struct {
|
||||
|
||||
type basicResponse struct {
|
||||
TBSResponseData responseData
|
||||
SignatureAlgorithm algorithmIdentifier
|
||||
SignatureAlgorithm pkix.AlgorithmIdentifier
|
||||
Signature asn1.BitString
|
||||
Certificates []asn1.RawValue "explicit,tag:0,optional"
|
||||
}
|
||||
@ -72,7 +61,7 @@ type basicResponse struct {
|
||||
type responseData struct {
|
||||
Raw asn1.RawContent
|
||||
Version int "optional,default:1,explicit,tag:0"
|
||||
RequestorName rdnSequence "optional,explicit,tag:1"
|
||||
RequestorName pkix.RDNSequence "optional,explicit,tag:1"
|
||||
KeyHash []byte "optional,explicit,tag:2"
|
||||
ProducedAt *time.Time
|
||||
Responses []singleResponse
|
||||
|
@ -64,7 +64,7 @@ func (priv *PrivateKey) Validate() os.Error {
|
||||
// easy for an attack to generate composites that pass this test.
|
||||
for _, prime := range priv.Primes {
|
||||
if !big.ProbablyPrime(prime, 20) {
|
||||
return os.ErrorString("Prime factor is composite")
|
||||
return os.ErrorString("prime factor is composite")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -159,7 +159,7 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err os.Err
|
||||
|
||||
key, err := x509.ParsePKCS1PrivateKey(keyDERBlock.Bytes)
|
||||
if err != nil {
|
||||
err = os.ErrorString("crypto/tls: failed to parse key")
|
||||
err = os.ErrorString("crypto/tls: failed to parse key: " + err.String())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
package x509
|
||||
|
||||
import (
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"strings"
|
||||
)
|
||||
@ -25,7 +26,7 @@ func NewCertPool() *CertPool {
|
||||
}
|
||||
}
|
||||
|
||||
func nameToKey(name *Name) string {
|
||||
func nameToKey(name *pkix.Name) string {
|
||||
return strings.Join(name.Country, ",") + "/" + strings.Join(name.Organization, ",") + "/" + strings.Join(name.OrganizationalUnit, ",") + "/" + name.CommonName
|
||||
}
|
||||
|
||||
|
@ -1,96 +0,0 @@
|
||||
// Copyright 2011 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 crl exposes low-level details of PKIX Certificate Revocation Lists
|
||||
// as specified in RFC 5280, section 5.
|
||||
package crl
|
||||
|
||||
import (
|
||||
"asn1"
|
||||
"bytes"
|
||||
"encoding/pem"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// CertificateList represents the ASN.1 structure of the same name. See RFC
|
||||
// 5280, section 5.1. Use crypto/x509/Certificate.CheckCRLSignature to verify
|
||||
// the signature.
|
||||
type CertificateList struct {
|
||||
TBSCertList TBSCertificateList
|
||||
SignatureAlgorithm AlgorithmIdentifier
|
||||
SignatureValue asn1.BitString
|
||||
}
|
||||
|
||||
// HasExpired returns true iff currentTimeSeconds is past the expiry time of
|
||||
// certList.
|
||||
func (certList *CertificateList) HasExpired(currentTimeSeconds int64) bool {
|
||||
return certList.TBSCertList.NextUpdate.Seconds() <= currentTimeSeconds
|
||||
}
|
||||
|
||||
// TBSCertificateList represents the ASN.1 structure of the same name. See RFC
|
||||
// 5280, section 5.1.
|
||||
type TBSCertificateList struct {
|
||||
Raw asn1.RawContent
|
||||
Version int "optional,default:2"
|
||||
Signature AlgorithmIdentifier
|
||||
Issuer asn1.RawValue
|
||||
ThisUpdate *time.Time
|
||||
NextUpdate *time.Time
|
||||
RevokedCertificates []RevokedCertificate "optional"
|
||||
Extensions []Extension "tag:0,optional,explicit"
|
||||
}
|
||||
|
||||
// AlgorithmIdentifier represents the ASN.1 structure of the same name. See RFC
|
||||
// 5280, section 4.1.1.2.
|
||||
type AlgorithmIdentifier struct {
|
||||
Algo asn1.ObjectIdentifier
|
||||
Params asn1.RawValue "optional"
|
||||
}
|
||||
|
||||
// AlgorithmIdentifier represents the ASN.1 structure of the same name. See RFC
|
||||
// 5280, section 5.1.
|
||||
type RevokedCertificate struct {
|
||||
SerialNumber asn1.RawValue
|
||||
RevocationTime *time.Time
|
||||
Extensions []Extension "optional"
|
||||
}
|
||||
|
||||
// AlgorithmIdentifier represents the ASN.1 structure of the same name. See RFC
|
||||
// 5280, section 4.2.
|
||||
type Extension struct {
|
||||
Id asn1.ObjectIdentifier
|
||||
IsCritial bool "optional"
|
||||
Value []byte
|
||||
}
|
||||
|
||||
// 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"
|
||||
|
||||
// Parse 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 Parse(crlBytes []byte) (certList *CertificateList, err os.Error) {
|
||||
if bytes.HasPrefix(crlBytes, pemCRLPrefix) {
|
||||
block, _ := pem.Decode(crlBytes)
|
||||
if block != nil && block.Type == pemType {
|
||||
crlBytes = block.Bytes
|
||||
}
|
||||
}
|
||||
return ParseDER(crlBytes)
|
||||
}
|
||||
|
||||
// ParseDER parses a DER encoded CRL from the given bytes.
|
||||
func ParseDER(derBytes []byte) (certList *CertificateList, err os.Error) {
|
||||
certList = new(CertificateList)
|
||||
_, err = asn1.Unmarshal(derBytes, certList)
|
||||
if err != nil {
|
||||
certList = nil
|
||||
}
|
||||
return
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
// Copyright 2011 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 crl
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func fromBase64(in string) []byte {
|
||||
out := make([]byte, base64.StdEncoding.DecodedLen(len(in)))
|
||||
_, err := base64.StdEncoding.Decode(out, []byte(in))
|
||||
if err != nil {
|
||||
panic("failed to base64 decode")
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func TestParseDER(t *testing.T) {
|
||||
derBytes := fromBase64(derCRLBase64)
|
||||
certList, err := ParseDER(derBytes)
|
||||
if err != nil {
|
||||
t.Errorf("error parsing: %s", err)
|
||||
return
|
||||
}
|
||||
numCerts := len(certList.TBSCertList.RevokedCertificates)
|
||||
expected := 88
|
||||
if numCerts != expected {
|
||||
t.Errorf("bad number of revoked certificates. got: %d want: %d", numCerts, expected)
|
||||
}
|
||||
|
||||
if certList.HasExpired(1302517272) {
|
||||
t.Errorf("CRL has expired (but shouldn't have)")
|
||||
}
|
||||
|
||||
// Can't check the signature here without a package cycle.
|
||||
}
|
||||
|
||||
func TestParsePEM(t *testing.T) {
|
||||
pemBytes := fromBase64(pemCRLBase64)
|
||||
certList, err := Parse(pemBytes)
|
||||
if err != nil {
|
||||
t.Errorf("error parsing: %s", err)
|
||||
return
|
||||
}
|
||||
numCerts := len(certList.TBSCertList.RevokedCertificates)
|
||||
expected := 2
|
||||
if numCerts != expected {
|
||||
t.Errorf("bad number of revoked certificates. got: %d want: %d", numCerts, expected)
|
||||
}
|
||||
|
||||
if certList.HasExpired(1302517272) {
|
||||
t.Errorf("CRL has expired (but shouldn't have)")
|
||||
}
|
||||
|
||||
// Can't check the signature here without a package cycle.
|
||||
}
|
||||
|
||||
const derCRLBase64 = "MIINqzCCDJMCAQEwDQYJKoZIhvcNAQEFBQAwVjEZMBcGA1UEAxMQUEtJIEZJTk1FQ0NBTklDQTEVMBMGA1UEChMMRklOTUVDQ0FOSUNBMRUwEwYDVQQLEwxGSU5NRUNDQU5JQ0ExCzAJBgNVBAYTAklUFw0xMTA1MDQxNjU3NDJaFw0xMTA1MDQyMDU3NDJaMIIMBzAhAg4Ze1od49Lt1qIXBydAzhcNMDkwNzE2MDg0MzIyWjAAMCECDl0HSL9bcZ1Ci/UHJ0DPFw0wOTA3MTYwODQzMTNaMAAwIQIOESB9tVAmX3cY7QcnQNAXDTA5MDcxNjA4NDUyMlowADAhAg4S1tGAQ3mHt8uVBydA1RcNMDkwODA0MTUyNTIyWjAAMCECDlQ249Y7vtC25ScHJ0DWFw0wOTA4MDQxNTI1MzdaMAAwIQIOISMop3NkA4PfYwcnQNkXDTA5MDgwNDExMDAzNFowADAhAg56/BMoS29KEShTBydA2hcNMDkwODA0MTEwMTAzWjAAMCECDnBp/22HPH5CSWoHJ0DbFw0wOTA4MDQxMDU0NDlaMAAwIQIOV9IP+8CD8bK+XAcnQNwXDTA5MDgwNDEwNTcxN1owADAhAg4v5aRz0IxWqYiXBydA3RcNMDkwODA0MTA1NzQ1WjAAMCECDlOU34VzvZAybQwHJ0DeFw0wOTA4MDQxMDU4MjFaMAAwIAINO4CD9lluIxcwBydBAxcNMDkwNzIyMTUzMTU5WjAAMCECDgOllfO8Y1QA7/wHJ0ExFw0wOTA3MjQxMTQxNDNaMAAwIQIOJBX7jbiCdRdyjgcnQUQXDTA5MDkxNjA5MzAwOFowADAhAg5iYSAgmDrlH/RZBydBRRcNMDkwOTE2MDkzMDE3WjAAMCECDmu6k6srP3jcMaQHJ0FRFw0wOTA4MDQxMDU2NDBaMAAwIQIOX8aHlO0V+WVH4QcnQVMXDTA5MDgwNDEwNTcyOVowADAhAg5flK2rg3NnsRgDBydBzhcNMTEwMjAxMTUzMzQ2WjAAMCECDg35yJDL1jOPTgoHJ0HPFw0xMTAyMDExNTM0MjZaMAAwIQIOMyFJ6+e9iiGVBQcnQdAXDTA5MDkxODEzMjAwNVowADAhAg5Emb/Oykucmn8fBydB1xcNMDkwOTIxMTAxMDQ3WjAAMCECDjQKCncV+MnUavMHJ0HaFw0wOTA5MjIwODE1MjZaMAAwIQIOaxiFUt3dpd+tPwcnQfQXDTEwMDYxODA4NDI1MVowADAhAg5G7P8nO0tkrMt7BydB9RcNMTAwNjE4MDg0MjMwWjAAMCECDmTCC3SXhmDRst4HJ0H2Fw0wOTA5MjgxMjA3MjBaMAAwIQIOHoGhUr/pRwzTKgcnQfcXDTA5MDkyODEyMDcyNFowADAhAg50wrcrCiw8mQmPBydCBBcNMTAwMjE2MTMwMTA2WjAAMCECDifWmkvwyhEqwEcHJ0IFFw0xMDAyMTYxMzAxMjBaMAAwIQIOfgPmlW9fg+osNgcnQhwXDTEwMDQxMzA5NTIwMFowADAhAg4YHAGuA6LgCk7tBydCHRcNMTAwNDEzMDk1MTM4WjAAMCECDi1zH1bxkNJhokAHJ0IsFw0xMDA0MTMwOTU5MzBaMAAwIQIOMipNccsb/wo2fwcnQi0XDTEwMDQxMzA5NTkwMFowADAhAg46lCmvPl4GpP6ABydCShcNMTAwMTE5MDk1MjE3WjAAMCECDjaTcaj+wBpcGAsHJ0JLFw0xMDAxMTkwOTUyMzRaMAAwIQIOOMC13EOrBuxIOQcnQloXDTEwMDIwMTA5NDcwNVowADAhAg5KmZl+krz4RsmrBydCWxcNMTAwMjAxMDk0NjQwWjAAMCECDmLG3zQJ/fzdSsUHJ0JiFw0xMDAzMDEwOTUxNDBaMAAwIQIOP39ksgHdojf4owcnQmMXDTEwMDMwMTA5NTExN1owADAhAg4LDQzvWNRlD6v9BydCZBcNMTAwMzAxMDk0NjIyWjAAMCECDkmNfeclaFhIaaUHJ0JlFw0xMDAzMDEwOTQ2MDVaMAAwIQIOT/qWWfpH/m8NTwcnQpQXDTEwMDUxMTA5MTgyMVowADAhAg5m/ksYxvCEgJSvBydClRcNMTAwNTExMDkxODAxWjAAMCECDgvf3Ohq6JOPU9AHJ0KWFw0xMDA1MTEwOTIxMjNaMAAwIQIOKSPas10z4jNVIQcnQpcXDTEwMDUxMTA5MjEwMlowADAhAg4mCWmhoZ3lyKCDBydCohcNMTEwNDI4MTEwMjI1WjAAMCECDkeiyRsBMK0Gvr4HJ0KjFw0xMTA0MjgxMTAyMDdaMAAwIQIOa09b/nH2+55SSwcnQq4XDTExMDQwMTA4Mjk0NlowADAhAg5O7M7iq7gGplr1BydCrxcNMTEwNDAxMDgzMDE3WjAAMCECDjlT6mJxUjTvyogHJ0K1Fw0xMTAxMjcxNTQ4NTJaMAAwIQIODS/l4UUFLe21NAcnQrYXDTExMDEyNzE1NDgyOFowADAhAg5lPRA0XdOUF6lSBydDHhcNMTEwMTI4MTQzNTA1WjAAMCECDixKX4fFGGpENwgHJ0MfFw0xMTAxMjgxNDM1MzBaMAAwIQIORNBkqsPnpKTtbAcnQ08XDTEwMDkwOTA4NDg0MlowADAhAg5QL+EMM3lohedEBydDUBcNMTAwOTA5MDg0ODE5WjAAMCECDlhDnHK+HiTRAXcHJ0NUFw0xMDEwMTkxNjIxNDBaMAAwIQIOdBFqAzq/INz53gcnQ1UXDTEwMTAxOTE2MjA0NFowADAhAg4OjR7s8MgKles1BydDWhcNMTEwMTI3MTY1MzM2WjAAMCECDmfR/elHee+d0SoHJ0NbFw0xMTAxMjcxNjUzNTZaMAAwIQIOBTKv2ui+KFMI+wcnQ5YXDTEwMDkxNTEwMjE1N1owADAhAg49F3c/GSah+oRUBydDmxcNMTEwMTI3MTczMjMzWjAAMCECDggv4I61WwpKFMMHJ0OcFw0xMTAxMjcxNzMyNTVaMAAwIQIOXx/Y8sEvwS10LAcnQ6UXDTExMDEyODExMjkzN1owADAhAg5LSLbnVrSKaw/9BydDphcNMTEwMTI4MTEyOTIwWjAAMCECDmFFoCuhKUeACQQHJ0PfFw0xMTAxMTExMDE3MzdaMAAwIQIOQTDdFh2fSPF6AAcnQ+AXDTExMDExMTEwMTcxMFowADAhAg5B8AOXX61FpvbbBydD5RcNMTAxMDA2MTAxNDM2WjAAMCECDh41P2Gmi7PkwI4HJ0PmFw0xMDEwMDYxMDE2MjVaMAAwIQIOWUHGLQCd+Ale9gcnQ/0XDTExMDUwMjA3NTYxMFowADAhAg5Z2c9AYkikmgWOBydD/hcNMTEwNTAyMDc1NjM0WjAAMCECDmf/UD+/h8nf+74HJ0QVFw0xMTA0MTUwNzI4MzNaMAAwIQIOICvj4epy3MrqfwcnRBYXDTExMDQxNTA3Mjg1NlowADAhAg4bouRMfOYqgv4xBydEHxcNMTEwMzA4MTYyNDI1WjAAMCECDhebWHGoKiTp7pEHJ0QgFw0xMTAzMDgxNjI0NDhaMAAwIQIOX+qnxxAqJ8LtawcnRDcXDTExMDEzMTE1MTIyOFowADAhAg4j0fICqZ+wkOdqBydEOBcNMTEwMTMxMTUxMTQxWjAAMCECDhmXjsV4SUpWtAMHJ0RLFw0xMTAxMjgxMTI0MTJaMAAwIQIODno/w+zG43kkTwcnREwXDTExMDEyODExMjM1MlowADAhAg4b1gc88767Fr+LBydETxcNMTEwMTI4MTEwMjA4WjAAMCECDn+M3Pa1w2nyFeUHJ0RQFw0xMTAxMjgxMDU4NDVaMAAwIQIOaduoyIH61tqybAcnRJUXDTEwMTIxNTA5NDMyMlowADAhAg4nLqQPkyi3ESAKBydElhcNMTAxMjE1MDk0MzM2WjAAMCECDi504NIMH8578gQHJ0SbFw0xMTAyMTQxNDA1NDFaMAAwIQIOGuaM8PDaC5u1egcnRJwXDTExMDIxNDE0MDYwNFowADAhAg4ehYq/BXGnB5PWBydEnxcNMTEwMjA0MDgwOTUxWjAAMCECDkSD4eS4FxW5H20HJ0SgFw0xMTAyMDQwODA5MjVaMAAwIQIOOCcb6ilYObt1egcnRKEXDTExMDEyNjEwNDEyOVowADAhAg58tISWCCwFnKGnBydEohcNMTEwMjA0MDgxMzQyWjAAMCECDn5rjtabY/L/WL0HJ0TJFw0xMTAyMDQxMTAzNDFaMAAwDQYJKoZIhvcNAQEFBQADggEBAGnF2Gs0+LNiYCW1Ipm83OXQYP/bd5tFFRzyz3iepFqNfYs4D68/QihjFoRHQoXEB0OEe1tvaVnnPGnEOpi6krwekquMxo4H88B5SlyiFIqemCOIss0SxlCFs69LmfRYvPPvPEhoXtQ3ZThe0UvKG83GOklhvGl6OaiRf4Mt+m8zOT4Wox/j6aOBK6cw6qKCdmD+Yj1rrNqFGg1CnSWMoD6S6mwNgkzwdBUJZ22BwrzAAo4RHa2Uy3ef1FjwD0XtU5N3uDSxGGBEDvOe5z82rps3E22FpAA8eYl8kaXtmWqyvYU0epp4brGuTxCuBMCAsxt/OjIjeNNQbBGkwxgfYA0="
|
||||
|
||||
const pemCRLBase64 = "LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tDQpNSUlCOWpDQ0FWOENBUUV3RFFZSktvWklodmNOQVFFRkJRQXdiREVhTUJnR0ExVUVDaE1SVWxOQklGTmxZM1Z5DQphWFI1SUVsdVl5NHhIakFjQmdOVkJBTVRGVkpUUVNCUWRXSnNhV01nVW05dmRDQkRRU0IyTVRFdU1Dd0dDU3FHDQpTSWIzRFFFSkFSWWZjbk5oYTJWdmJuSnZiM1J6YVdkdVFISnpZWE5sWTNWeWFYUjVMbU52YlJjTk1URXdNakl6DQpNVGt5T0RNd1doY05NVEV3T0RJeU1Ua3lPRE13V2pDQmpEQktBaEVBckRxb2g5RkhKSFhUN09QZ3V1bjQrQmNODQpNRGt4TVRBeU1UUXlOekE1V2pBbU1Bb0dBMVVkRlFRRENnRUpNQmdHQTFVZEdBUVJHQTh5TURBNU1URXdNakUwDQpNalExTlZvd1BnSVJBTEd6blowOTVQQjVhQU9MUGc1N2ZNTVhEVEF5TVRBeU16RTBOVEF4TkZvd0dqQVlCZ05WDQpIUmdFRVJnUE1qQXdNakV3TWpNeE5EVXdNVFJhb0RBd0xqQWZCZ05WSFNNRUdEQVdnQlQxVERGNlVRTS9MTmVMDQpsNWx2cUhHUXEzZzltekFMQmdOVkhSUUVCQUlDQUlRd0RRWUpLb1pJaHZjTkFRRUZCUUFEZ1lFQUZVNUFzNk16DQpxNVBSc2lmYW9iUVBHaDFhSkx5QytNczVBZ2MwYld5QTNHQWR4dXI1U3BQWmVSV0NCamlQL01FSEJXSkNsQkhQDQpHUmNxNXlJZDNFakRrYUV5eFJhK2k2N0x6dmhJNmMyOUVlNks5cFNZd2ppLzdSVWhtbW5Qclh0VHhsTDBsckxyDQptUVFKNnhoRFJhNUczUUE0Q21VZHNITnZicnpnbUNZcHZWRT0NCi0tLS0tRU5EIFg1MDkgQ1JMLS0tLS0NCg0K"
|
@ -4,8 +4,8 @@
|
||||
|
||||
include ../../../../Make.inc
|
||||
|
||||
TARG=crypto/x509/crl
|
||||
TARG=crypto/x509/pkix
|
||||
GOFILES=\
|
||||
crl.go\
|
||||
pkix.go\
|
||||
|
||||
include ../../../../Make.pkg
|
167
src/pkg/crypto/x509/pkix/pkix.go
Normal file
167
src/pkg/crypto/x509/pkix/pkix.go
Normal file
@ -0,0 +1,167 @@
|
||||
// Copyright 2011 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 pkix contains shared, low level structures used for ASN.1 parsing
|
||||
// and serialization of X.509 certificates, CRL and OCSP.
|
||||
package pkix
|
||||
|
||||
import (
|
||||
"asn1"
|
||||
"big"
|
||||
"time"
|
||||
)
|
||||
|
||||
// AlgorithmIdentifier represents the ASN.1 structure of the same name. See RFC
|
||||
// 5280, section 4.1.1.2.
|
||||
type AlgorithmIdentifier struct {
|
||||
Algorithm asn1.ObjectIdentifier
|
||||
Parameters asn1.RawValue "optional"
|
||||
}
|
||||
|
||||
type RDNSequence []RelativeDistinguishedNameSET
|
||||
|
||||
type RelativeDistinguishedNameSET []AttributeTypeAndValue
|
||||
|
||||
type AttributeTypeAndValue struct {
|
||||
Type asn1.ObjectIdentifier
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
// Extension represents the ASN.1 structure of the same name. See RFC
|
||||
// 5280, section 4.2.
|
||||
type Extension struct {
|
||||
Id asn1.ObjectIdentifier
|
||||
Critical bool "optional"
|
||||
Value []byte
|
||||
}
|
||||
|
||||
// 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
|
||||
Locality, Province []string
|
||||
StreetAddress, PostalCode []string
|
||||
SerialNumber, CommonName 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 = append(n.Country, value)
|
||||
case 7:
|
||||
n.Locality = append(n.Locality, value)
|
||||
case 8:
|
||||
n.Province = append(n.Province, value)
|
||||
case 9:
|
||||
n.StreetAddress = append(n.StreetAddress, value)
|
||||
case 10:
|
||||
n.Organization = append(n.Organization, value)
|
||||
case 11:
|
||||
n.OrganizationalUnit = append(n.OrganizationalUnit, value)
|
||||
case 17:
|
||||
n.PostalCode = append(n.PostalCode, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
oidCountry = []int{2, 5, 4, 6}
|
||||
oidOrganization = []int{2, 5, 4, 10}
|
||||
oidOrganizationalUnit = []int{2, 5, 4, 11}
|
||||
oidCommonName = []int{2, 5, 4, 3}
|
||||
oidSerialNumber = []int{2, 5, 4, 5}
|
||||
oidLocality = []int{2, 5, 4, 7}
|
||||
oidProvince = []int{2, 5, 4, 8}
|
||||
oidStreetAddress = []int{2, 5, 4, 9}
|
||||
oidPostalCode = []int{2, 5, 4, 17}
|
||||
)
|
||||
|
||||
// appendRDNs appends a relativeDistinguishedNameSET to the given RDNSequence
|
||||
// and returns the new value. The relativeDistinguishedNameSET contains an
|
||||
// attributeTypeAndValue for each of the given values. See RFC 5280, A.1, and
|
||||
// search for AttributeTypeAndValue.
|
||||
func appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentifier) RDNSequence {
|
||||
if len(values) == 0 {
|
||||
return in
|
||||
}
|
||||
|
||||
s := make([]AttributeTypeAndValue, len(values))
|
||||
for i, value := range values {
|
||||
s[i].Type = oid
|
||||
s[i].Value = value
|
||||
}
|
||||
|
||||
return append(in, s)
|
||||
}
|
||||
|
||||
func (n Name) ToRDNSequence() (ret RDNSequence) {
|
||||
ret = appendRDNs(ret, n.Country, oidCountry)
|
||||
ret = appendRDNs(ret, n.Organization, oidOrganization)
|
||||
ret = appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit)
|
||||
ret = appendRDNs(ret, n.Locality, oidLocality)
|
||||
ret = appendRDNs(ret, n.Province, oidProvince)
|
||||
ret = appendRDNs(ret, n.StreetAddress, oidStreetAddress)
|
||||
ret = appendRDNs(ret, n.PostalCode, oidPostalCode)
|
||||
if len(n.CommonName) > 0 {
|
||||
ret = appendRDNs(ret, []string{n.CommonName}, oidCommonName)
|
||||
}
|
||||
if len(n.SerialNumber) > 0 {
|
||||
ret = appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber)
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// CertificateList represents the ASN.1 structure of the same name. See RFC
|
||||
// 5280, section 5.1. Use Certificate.CheckCRLSignature to verify the
|
||||
// signature.
|
||||
type CertificateList struct {
|
||||
TBSCertList TBSCertificateList
|
||||
SignatureAlgorithm AlgorithmIdentifier
|
||||
SignatureValue asn1.BitString
|
||||
}
|
||||
|
||||
// HasExpired returns true iff currentTimeSeconds is past the expiry time of
|
||||
// certList.
|
||||
func (certList *CertificateList) HasExpired(currentTimeSeconds int64) bool {
|
||||
return certList.TBSCertList.NextUpdate.Seconds() <= currentTimeSeconds
|
||||
}
|
||||
|
||||
// TBSCertificateList represents the ASN.1 structure of the same name. See RFC
|
||||
// 5280, section 5.1.
|
||||
type TBSCertificateList struct {
|
||||
Raw asn1.RawContent
|
||||
Version int "optional,default:2"
|
||||
Signature AlgorithmIdentifier
|
||||
Issuer RDNSequence
|
||||
ThisUpdate *time.Time
|
||||
NextUpdate *time.Time
|
||||
RevokedCertificates []RevokedCertificate "optional"
|
||||
Extensions []Extension "tag:0,optional,explicit"
|
||||
}
|
||||
|
||||
// RevokedCertificate represents the ASN.1 structure of the same name. See RFC
|
||||
// 5280, section 5.1.
|
||||
type RevokedCertificate struct {
|
||||
SerialNumber *big.Int
|
||||
RevocationTime *time.Time
|
||||
Extensions []Extension "optional"
|
||||
}
|
@ -14,7 +14,8 @@ import (
|
||||
"crypto/dsa"
|
||||
"crypto/rsa"
|
||||
"crypto/sha1"
|
||||
"crypto/x509/crl"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
@ -23,30 +24,25 @@ import (
|
||||
// pkcs1PrivateKey is a structure which mirrors the PKCS#1 ASN.1 for an RSA private key.
|
||||
type pkcs1PrivateKey struct {
|
||||
Version int
|
||||
N asn1.RawValue
|
||||
N *big.Int
|
||||
E int
|
||||
D asn1.RawValue
|
||||
P asn1.RawValue
|
||||
Q asn1.RawValue
|
||||
D *big.Int
|
||||
P *big.Int
|
||||
Q *big.Int
|
||||
// We ignore these values, if present, because rsa will calculate them.
|
||||
Dp asn1.RawValue "optional"
|
||||
Dq asn1.RawValue "optional"
|
||||
Qinv asn1.RawValue "optional"
|
||||
Dp *big.Int "optional"
|
||||
Dq *big.Int "optional"
|
||||
Qinv *big.Int "optional"
|
||||
|
||||
AdditionalPrimes []pkcs1AdditionalRSAPrime "optional"
|
||||
}
|
||||
|
||||
type pkcs1AdditionalRSAPrime struct {
|
||||
Prime asn1.RawValue
|
||||
Prime *big.Int
|
||||
|
||||
// We ignore these values because rsa will calculate them.
|
||||
Exp asn1.RawValue
|
||||
Coeff 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
|
||||
Exp *big.Int
|
||||
Coeff *big.Int
|
||||
}
|
||||
|
||||
// ParsePKCS1PrivateKey returns an RSA private key from its ASN.1 PKCS#1 DER encoded form.
|
||||
@ -65,29 +61,25 @@ func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err os.Error) {
|
||||
return nil, os.ErrorString("x509: unsupported private key version")
|
||||
}
|
||||
|
||||
if !rawValueIsInteger(&priv.N) ||
|
||||
!rawValueIsInteger(&priv.D) ||
|
||||
!rawValueIsInteger(&priv.P) ||
|
||||
!rawValueIsInteger(&priv.Q) {
|
||||
err = asn1.StructuralError{"tags don't match"}
|
||||
return
|
||||
if priv.N.Sign() <= 0 || priv.D.Sign() <= 0 || priv.P.Sign() <= 0 || priv.Q.Sign() <= 0 {
|
||||
return nil, os.ErrorString("private key contains zero or negative value")
|
||||
}
|
||||
|
||||
key = new(rsa.PrivateKey)
|
||||
key.PublicKey = rsa.PublicKey{
|
||||
E: priv.E,
|
||||
N: new(big.Int).SetBytes(priv.N.Bytes),
|
||||
N: priv.N,
|
||||
}
|
||||
|
||||
key.D = new(big.Int).SetBytes(priv.D.Bytes)
|
||||
key.D = priv.D
|
||||
key.Primes = make([]*big.Int, 2+len(priv.AdditionalPrimes))
|
||||
key.Primes[0] = new(big.Int).SetBytes(priv.P.Bytes)
|
||||
key.Primes[1] = new(big.Int).SetBytes(priv.Q.Bytes)
|
||||
key.Primes[0] = priv.P
|
||||
key.Primes[1] = priv.Q
|
||||
for i, a := range priv.AdditionalPrimes {
|
||||
if !rawValueIsInteger(&a.Prime) {
|
||||
return nil, asn1.StructuralError{"tags don't match"}
|
||||
if a.Prime.Sign() <= 0 {
|
||||
return nil, os.ErrorString("private key contains zero or negative prime")
|
||||
}
|
||||
key.Primes[i+2] = new(big.Int).SetBytes(a.Prime.Bytes)
|
||||
key.Primes[i+2] = a.Prime
|
||||
// We ignore the other two values because rsa will calculate
|
||||
// them as needed.
|
||||
}
|
||||
@ -101,19 +93,6 @@ func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err os.Error) {
|
||||
return
|
||||
}
|
||||
|
||||
// rawValueForBig returns an asn1.RawValue which represents the given integer.
|
||||
func rawValueForBig(n *big.Int) asn1.RawValue {
|
||||
b := n.Bytes()
|
||||
if n.Sign() >= 0 && len(b) > 0 && b[0]&0x80 != 0 {
|
||||
// This positive number would be interpreted as a negative
|
||||
// number in ASN.1 because the MSB is set.
|
||||
padded := make([]byte, len(b)+1)
|
||||
copy(padded[1:], b)
|
||||
b = padded
|
||||
}
|
||||
return asn1.RawValue{Tag: 2, Bytes: b}
|
||||
}
|
||||
|
||||
// MarshalPKCS1PrivateKey converts a private key to ASN.1 DER encoded form.
|
||||
func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte {
|
||||
key.Precompute()
|
||||
@ -125,21 +104,21 @@ func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte {
|
||||
|
||||
priv := pkcs1PrivateKey{
|
||||
Version: version,
|
||||
N: rawValueForBig(key.N),
|
||||
N: key.N,
|
||||
E: key.PublicKey.E,
|
||||
D: rawValueForBig(key.D),
|
||||
P: rawValueForBig(key.Primes[0]),
|
||||
Q: rawValueForBig(key.Primes[1]),
|
||||
Dp: rawValueForBig(key.Precomputed.Dp),
|
||||
Dq: rawValueForBig(key.Precomputed.Dq),
|
||||
Qinv: rawValueForBig(key.Precomputed.Qinv),
|
||||
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 = rawValueForBig(key.Primes[2+i])
|
||||
priv.AdditionalPrimes[i].Exp = rawValueForBig(values.Exp)
|
||||
priv.AdditionalPrimes[i].Coeff = rawValueForBig(values.Coeff)
|
||||
priv.AdditionalPrimes[i].Prime = key.Primes[2+i]
|
||||
priv.AdditionalPrimes[i].Exp = values.Exp
|
||||
priv.AdditionalPrimes[i].Coeff = values.Coeff
|
||||
}
|
||||
|
||||
b, _ := asn1.Marshal(priv)
|
||||
@ -151,44 +130,30 @@ func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte {
|
||||
type certificate struct {
|
||||
Raw asn1.RawContent
|
||||
TBSCertificate tbsCertificate
|
||||
SignatureAlgorithm algorithmIdentifier
|
||||
SignatureAlgorithm pkix.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
|
||||
SerialNumber *big.Int
|
||||
SignatureAlgorithm pkix.AlgorithmIdentifier
|
||||
Issuer pkix.RDNSequence
|
||||
Validity validity
|
||||
Subject rdnSequence
|
||||
Subject pkix.RDNSequence
|
||||
PublicKey publicKeyInfo
|
||||
UniqueId asn1.BitString "optional,tag:1"
|
||||
SubjectUniqueId asn1.BitString "optional,tag:2"
|
||||
Extensions []extension "optional,explicit,tag:3"
|
||||
Extensions []pkix.Extension "optional,explicit,tag:3"
|
||||
}
|
||||
|
||||
type dsaAlgorithmParameters struct {
|
||||
P, Q, G asn1.RawValue
|
||||
P, Q, G *big.Int
|
||||
}
|
||||
|
||||
type dsaSignature struct {
|
||||
R, S asn1.RawValue
|
||||
}
|
||||
|
||||
type algorithmIdentifier struct {
|
||||
Algorithm asn1.ObjectIdentifier
|
||||
Parameters asn1.RawValue "optional"
|
||||
}
|
||||
|
||||
type rdnSequence []relativeDistinguishedNameSET
|
||||
|
||||
type relativeDistinguishedNameSET []attributeTypeAndValue
|
||||
|
||||
type attributeTypeAndValue struct {
|
||||
Type asn1.ObjectIdentifier
|
||||
Value interface{}
|
||||
R, S *big.Int
|
||||
}
|
||||
|
||||
type validity struct {
|
||||
@ -197,16 +162,10 @@ type validity struct {
|
||||
|
||||
type publicKeyInfo struct {
|
||||
Raw asn1.RawContent
|
||||
Algorithm algorithmIdentifier
|
||||
Algorithm pkix.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"
|
||||
@ -234,100 +193,6 @@ const (
|
||||
DSA
|
||||
)
|
||||
|
||||
// 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
|
||||
Locality, Province []string
|
||||
StreetAddress, PostalCode []string
|
||||
SerialNumber, CommonName 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 = append(n.Country, value)
|
||||
case 7:
|
||||
n.Locality = append(n.Locality, value)
|
||||
case 8:
|
||||
n.Province = append(n.Province, value)
|
||||
case 9:
|
||||
n.StreetAddress = append(n.StreetAddress, value)
|
||||
case 10:
|
||||
n.Organization = append(n.Organization, value)
|
||||
case 11:
|
||||
n.OrganizationalUnit = append(n.OrganizationalUnit, value)
|
||||
case 17:
|
||||
n.PostalCode = append(n.PostalCode, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
oidCountry = []int{2, 5, 4, 6}
|
||||
oidOrganization = []int{2, 5, 4, 10}
|
||||
oidOrganizationalUnit = []int{2, 5, 4, 11}
|
||||
oidCommonName = []int{2, 5, 4, 3}
|
||||
oidSerialNumber = []int{2, 5, 4, 5}
|
||||
oidLocality = []int{2, 5, 4, 7}
|
||||
oidProvince = []int{2, 5, 4, 8}
|
||||
oidStreetAddress = []int{2, 5, 4, 9}
|
||||
oidPostalCode = []int{2, 5, 4, 17}
|
||||
)
|
||||
|
||||
// appendRDNs appends a relativeDistinguishedNameSET to the given rdnSequence
|
||||
// and returns the new value. The relativeDistinguishedNameSET contains an
|
||||
// attributeTypeAndValue for each of the given values. See RFC 5280, A.1, and
|
||||
// search for AttributeTypeAndValue.
|
||||
func appendRDNs(in rdnSequence, values []string, oid asn1.ObjectIdentifier) rdnSequence {
|
||||
if len(values) == 0 {
|
||||
return in
|
||||
}
|
||||
|
||||
s := make([]attributeTypeAndValue, len(values))
|
||||
for i, value := range values {
|
||||
s[i].Type = oid
|
||||
s[i].Value = value
|
||||
}
|
||||
|
||||
return append(in, s)
|
||||
}
|
||||
|
||||
func (n Name) toRDNSequence() (ret rdnSequence) {
|
||||
ret = appendRDNs(ret, n.Country, oidCountry)
|
||||
ret = appendRDNs(ret, n.Organization, oidOrganization)
|
||||
ret = appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit)
|
||||
ret = appendRDNs(ret, n.Locality, oidLocality)
|
||||
ret = appendRDNs(ret, n.Province, oidProvince)
|
||||
ret = appendRDNs(ret, n.StreetAddress, oidStreetAddress)
|
||||
ret = appendRDNs(ret, n.PostalCode, oidPostalCode)
|
||||
if len(n.CommonName) > 0 {
|
||||
ret = appendRDNs(ret, []string{n.CommonName}, oidCommonName)
|
||||
}
|
||||
if len(n.SerialNumber) > 0 {
|
||||
ret = appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber)
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// OIDs for signature algorithms
|
||||
//
|
||||
// pkcs-1 OBJECT IDENTIFIER ::= {
|
||||
@ -483,9 +348,9 @@ type Certificate struct {
|
||||
PublicKey interface{}
|
||||
|
||||
Version int
|
||||
SerialNumber []byte
|
||||
Issuer Name
|
||||
Subject Name
|
||||
SerialNumber *big.Int
|
||||
Issuer pkix.Name
|
||||
Subject pkix.Name
|
||||
NotBefore, NotAfter *time.Time // Validity bounds.
|
||||
KeyUsage KeyUsage
|
||||
|
||||
@ -591,12 +456,10 @@ func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature
|
||||
if _, err := asn1.Unmarshal(signature, dsaSig); err != nil {
|
||||
return err
|
||||
}
|
||||
if !rawValueIsInteger(&dsaSig.R) || !rawValueIsInteger(&dsaSig.S) {
|
||||
return asn1.StructuralError{"tags don't match"}
|
||||
if dsaSig.R.Sign() <= 0 || dsaSig.S.Sign() <= 0 {
|
||||
return os.ErrorString("DSA signature contained zero or negative values")
|
||||
}
|
||||
r := new(big.Int).SetBytes(dsaSig.R.Bytes)
|
||||
s := new(big.Int).SetBytes(dsaSig.S.Bytes)
|
||||
if !dsa.Verify(pub, digest, r, s) {
|
||||
if !dsa.Verify(pub, digest, dsaSig.R, dsaSig.S) {
|
||||
return os.ErrorString("DSA verification failure")
|
||||
}
|
||||
return
|
||||
@ -605,8 +468,8 @@ func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature
|
||||
}
|
||||
|
||||
// CheckCRLSignature checks that the signature in crl is from c.
|
||||
func (c *Certificate) CheckCRLSignature(crl *crl.CertificateList) (err os.Error) {
|
||||
algo := getSignatureAlgorithmFromOID(crl.SignatureAlgorithm.Algo)
|
||||
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())
|
||||
}
|
||||
|
||||
@ -622,7 +485,7 @@ type basicConstraints struct {
|
||||
}
|
||||
|
||||
type rsaPublicKey struct {
|
||||
N asn1.RawValue
|
||||
N *big.Int
|
||||
E int
|
||||
}
|
||||
|
||||
@ -654,42 +517,33 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{
|
||||
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),
|
||||
N: p.N,
|
||||
}
|
||||
return pub, nil
|
||||
case DSA:
|
||||
p := new(asn1.RawValue)
|
||||
_, err := asn1.Unmarshal(asn1Data, p)
|
||||
var p *big.Int
|
||||
_, err := asn1.Unmarshal(asn1Data, &p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !rawValueIsInteger(p) {
|
||||
return nil, asn1.StructuralError{"tags don't match"}
|
||||
}
|
||||
paramsData := keyData.Algorithm.Parameters.FullBytes
|
||||
params := new(dsaAlgorithmParameters)
|
||||
_, err = asn1.Unmarshal(paramsData, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !rawValueIsInteger(¶ms.P) ||
|
||||
!rawValueIsInteger(¶ms.Q) ||
|
||||
!rawValueIsInteger(¶ms.G) {
|
||||
return nil, asn1.StructuralError{"tags don't match"}
|
||||
if p.Sign() <= 0 || params.P.Sign() <= 0 || params.Q.Sign() <= 0 || params.G.Sign() <= 0 {
|
||||
return nil, os.ErrorString("zero or negative DSA parameter")
|
||||
}
|
||||
pub := &dsa.PublicKey{
|
||||
Parameters: dsa.Parameters{
|
||||
P: new(big.Int).SetBytes(params.P.Bytes),
|
||||
Q: new(big.Int).SetBytes(params.Q.Bytes),
|
||||
G: new(big.Int).SetBytes(params.G.Bytes),
|
||||
P: params.P,
|
||||
Q: params.Q,
|
||||
G: params.G,
|
||||
},
|
||||
Y: new(big.Int).SetBytes(p.Bytes),
|
||||
Y: p,
|
||||
}
|
||||
return pub, nil
|
||||
default:
|
||||
@ -716,10 +570,14 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if in.TBSCertificate.SerialNumber.Sign() < 0 {
|
||||
return nil, os.ErrorString("negative serial number")
|
||||
}
|
||||
|
||||
out.Version = in.TBSCertificate.Version + 1
|
||||
out.SerialNumber = in.TBSCertificate.SerialNumber.Bytes
|
||||
out.Issuer.fillFromRDNSequence(&in.TBSCertificate.Issuer)
|
||||
out.Subject.fillFromRDNSequence(&in.TBSCertificate.Subject)
|
||||
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
|
||||
|
||||
@ -977,8 +835,8 @@ var (
|
||||
oidExtensionNameConstraints = []int{2, 5, 29, 30}
|
||||
)
|
||||
|
||||
func buildExtensions(template *Certificate) (ret []extension, err os.Error) {
|
||||
ret = make([]extension, 7 /* maximum number of elements. */ )
|
||||
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 {
|
||||
@ -1095,7 +953,7 @@ var (
|
||||
// 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: asn1.RawValue{Tag: 2, Bytes: pub.N.Bytes()},
|
||||
N: pub.N,
|
||||
E: pub.E,
|
||||
})
|
||||
if err != nil {
|
||||
@ -1114,12 +972,12 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.P
|
||||
encodedPublicKey := asn1.BitString{BitLength: len(asn1PublicKey) * 8, Bytes: asn1PublicKey}
|
||||
c := tbsCertificate{
|
||||
Version: 2,
|
||||
SerialNumber: asn1.RawValue{Bytes: template.SerialNumber, Tag: 2},
|
||||
SignatureAlgorithm: algorithmIdentifier{Algorithm: oidSHA1WithRSA},
|
||||
Issuer: parent.Subject.toRDNSequence(),
|
||||
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, algorithmIdentifier{Algorithm: oidRSA}, encodedPublicKey},
|
||||
Subject: template.Subject.ToRDNSequence(),
|
||||
PublicKey: publicKeyInfo{nil, pkix.AlgorithmIdentifier{Algorithm: oidRSA}, encodedPublicKey},
|
||||
Extensions: extensions,
|
||||
}
|
||||
|
||||
@ -1142,8 +1000,75 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.P
|
||||
cert, err = asn1.Marshal(certificate{
|
||||
nil,
|
||||
c,
|
||||
algorithmIdentifier{Algorithm: oidSHA1WithRSA},
|
||||
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},
|
||||
})
|
||||
}
|
||||
|
@ -10,6 +10,8 @@ import (
|
||||
"crypto/dsa"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/pem"
|
||||
"testing"
|
||||
@ -207,8 +209,8 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
|
||||
}
|
||||
|
||||
template := Certificate{
|
||||
SerialNumber: []byte{1},
|
||||
Subject: Name{
|
||||
SerialNumber: big.NewInt(1),
|
||||
Subject: pkix.Name{
|
||||
CommonName: "test.example.com",
|
||||
Organization: []string{"Acme Co"},
|
||||
},
|
||||
@ -331,3 +333,99 @@ func TestVerifyCertificateWithDSASignature(t *testing.T) {
|
||||
t.Fatalf("DSA Certificate verfication failed: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
const pemCertificate = `-----BEGIN CERTIFICATE-----
|
||||
MIIB5DCCAZCgAwIBAgIBATALBgkqhkiG9w0BAQUwLTEQMA4GA1UEChMHQWNtZSBDbzEZMBcGA1UE
|
||||
AxMQdGVzdC5leGFtcGxlLmNvbTAeFw03MDAxMDEwMDE2NDBaFw03MDAxMDIwMzQ2NDBaMC0xEDAO
|
||||
BgNVBAoTB0FjbWUgQ28xGTAXBgNVBAMTEHRlc3QuZXhhbXBsZS5jb20wWjALBgkqhkiG9w0BAQED
|
||||
SwAwSAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0fd7Ai2KW5ToIwzFo
|
||||
fvJcS/STa6HA5gQenRUCAwEAAaOBnjCBmzAOBgNVHQ8BAf8EBAMCAAQwDwYDVR0TAQH/BAUwAwEB
|
||||
/zANBgNVHQ4EBgQEAQIDBDAPBgNVHSMECDAGgAQBAgMEMBsGA1UdEQQUMBKCEHRlc3QuZXhhbXBs
|
||||
ZS5jb20wDwYDVR0gBAgwBjAEBgIqAzAqBgNVHR4EIzAhoB8wDoIMLmV4YW1wbGUuY29tMA2CC2V4
|
||||
YW1wbGUuY29tMAsGCSqGSIb3DQEBBQNBAHKZKoS1wEQOGhgklx4+/yFYQlnqwKXvar/ZecQvJwui
|
||||
0seMQnwBhwdBkHfVIU2Fu5VUMRyxlf0ZNaDXcpU581k=
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
func TestCRLCreation(t *testing.T) {
|
||||
block, _ := pem.Decode([]byte(pemPrivateKey))
|
||||
priv, _ := ParsePKCS1PrivateKey(block.Bytes)
|
||||
block, _ = pem.Decode([]byte(pemCertificate))
|
||||
cert, _ := ParseCertificate(block.Bytes)
|
||||
|
||||
now := time.SecondsToUTC(1000)
|
||||
expiry := time.SecondsToUTC(10000)
|
||||
|
||||
revokedCerts := []pkix.RevokedCertificate{
|
||||
{
|
||||
SerialNumber: big.NewInt(1),
|
||||
RevocationTime: now,
|
||||
},
|
||||
{
|
||||
SerialNumber: big.NewInt(42),
|
||||
RevocationTime: now,
|
||||
},
|
||||
}
|
||||
|
||||
crlBytes, err := cert.CreateCRL(rand.Reader, priv, revokedCerts, now, expiry)
|
||||
if err != nil {
|
||||
t.Errorf("error creating CRL: %s", err)
|
||||
}
|
||||
|
||||
_, err = ParseDERCRL(crlBytes)
|
||||
if err != nil {
|
||||
t.Errorf("error reparsing CRL: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func fromBase64(in string) []byte {
|
||||
out := make([]byte, base64.StdEncoding.DecodedLen(len(in)))
|
||||
_, err := base64.StdEncoding.Decode(out, []byte(in))
|
||||
if err != nil {
|
||||
panic("failed to base64 decode")
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func TestParseDERCRL(t *testing.T) {
|
||||
derBytes := fromBase64(derCRLBase64)
|
||||
certList, err := ParseDERCRL(derBytes)
|
||||
if err != nil {
|
||||
t.Errorf("error parsing: %s", err)
|
||||
return
|
||||
}
|
||||
numCerts := len(certList.TBSCertList.RevokedCertificates)
|
||||
expected := 88
|
||||
if numCerts != expected {
|
||||
t.Errorf("bad number of revoked certificates. got: %d want: %d", numCerts, expected)
|
||||
}
|
||||
|
||||
if certList.HasExpired(1302517272) {
|
||||
t.Errorf("CRL has expired (but shouldn't have)")
|
||||
}
|
||||
|
||||
// Can't check the signature here without a package cycle.
|
||||
}
|
||||
|
||||
func TestParsePEMCRL(t *testing.T) {
|
||||
pemBytes := fromBase64(pemCRLBase64)
|
||||
certList, err := ParseCRL(pemBytes)
|
||||
if err != nil {
|
||||
t.Errorf("error parsing: %s", err)
|
||||
return
|
||||
}
|
||||
numCerts := len(certList.TBSCertList.RevokedCertificates)
|
||||
expected := 2
|
||||
if numCerts != expected {
|
||||
t.Errorf("bad number of revoked certificates. got: %d want: %d", numCerts, expected)
|
||||
}
|
||||
|
||||
if certList.HasExpired(1302517272) {
|
||||
t.Errorf("CRL has expired (but shouldn't have)")
|
||||
}
|
||||
|
||||
// Can't check the signature here without a package cycle.
|
||||
}
|
||||
|
||||
const derCRLBase64 = "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"
|
||||
|
||||
const pemCRLBase64 = "LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tDQpNSUlCOWpDQ0FWOENBUUV3RFFZSktvWklodmNOQVFFRkJRQXdiREVhTUJnR0ExVUVDaE1SVWxOQklGTmxZM1Z5DQphWFI1SUVsdVl5NHhIakFjQmdOVkJBTVRGVkpUUVNCUWRXSnNhV01nVW05dmRDQkRRU0IyTVRFdU1Dd0dDU3FHDQpTSWIzRFFFSkFSWWZjbk5oYTJWdmJuSnZiM1J6YVdkdVFISnpZWE5sWTNWeWFYUjVMbU52YlJjTk1URXdNakl6DQpNVGt5T0RNd1doY05NVEV3T0RJeU1Ua3lPRE13V2pDQmpEQktBaEVBckRxb2g5RkhKSFhUN09QZ3V1bjQrQmNODQpNRGt4TVRBeU1UUXlOekE1V2pBbU1Bb0dBMVVkRlFRRENnRUpNQmdHQTFVZEdBUVJHQTh5TURBNU1URXdNakUwDQpNalExTlZvd1BnSVJBTEd6blowOTVQQjVhQU9MUGc1N2ZNTVhEVEF5TVRBeU16RTBOVEF4TkZvd0dqQVlCZ05WDQpIUmdFRVJnUE1qQXdNakV3TWpNeE5EVXdNVFJhb0RBd0xqQWZCZ05WSFNNRUdEQVdnQlQxVERGNlVRTS9MTmVMDQpsNWx2cUhHUXEzZzltekFMQmdOVkhSUUVCQUlDQUlRd0RRWUpLb1pJaHZjTkFRRUZCUUFEZ1lFQUZVNUFzNk16DQpxNVBSc2lmYW9iUVBHaDFhSkx5QytNczVBZ2MwYld5QTNHQWR4dXI1U3BQWmVSV0NCamlQL01FSEJXSkNsQkhQDQpHUmNxNXlJZDNFakRrYUV5eFJhK2k2N0x6dmhJNmMyOUVlNks5cFNZd2ppLzdSVWhtbW5Qclh0VHhsTDBsckxyDQptUVFKNnhoRFJhNUczUUE0Q21VZHNITnZicnpnbUNZcHZWRT0NCi0tLS0tRU5EIFg1MDkgQ1JMLS0tLS0NCg0K"
|
||||
|
@ -108,29 +108,24 @@ func (s *Server) CloseClientConnections() {
|
||||
// "127.0.0.1" and "[::1]", expiring at the last second of 2049 (the end
|
||||
// of ASN.1 time).
|
||||
var localhostCert = []byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIBwTCCASugAwIBAgIBADALBgkqhkiG9w0BAQUwADAeFw0xMTAzMzEyMDI1MDda
|
||||
Fw00OTEyMzEyMzU5NTlaMAAwggCdMAsGCSqGSIb3DQEBAQOCAIwAMIIAhwKCAIB6
|
||||
oy4iT42G6qk+GGn5VL5JlnJT6ZG5cqaMNFaNGlIxNb6CPUZLKq2sM3gRaimsktIw
|
||||
nNAcNwQGHpe1tZo+J/Pl04JTt71Y/TTAxy7OX27aZf1Rpt0SjdZ7vTPnFDPNsHGe
|
||||
KBKvPt55l2+YKjkZmV7eRevsVbpkNvNGB+T5d4Ge/wIBA6NPME0wDgYDVR0PAQH/
|
||||
BAQDAgCgMA0GA1UdDgQGBAQBAgMEMA8GA1UdIwQIMAaABAECAwQwGwYDVR0RBBQw
|
||||
EoIJMTI3LjAuMC4xggVbOjoxXTALBgkqhkiG9w0BAQUDggCBAHC3gbdvc44vs+wD
|
||||
g2kONiENnx8WKc0UTGg/TOXS3gaRb+CUIQtHWja65l8rAfclEovjHgZ7gx8brO0W
|
||||
JuC6p3MUAKsgOssIrrRIx2rpnfcmFVMzguCmrMNVmKUAalw18Yp0F72xYAIitVQl
|
||||
kJrLdIhBajcJRYu/YGltHQRaXuVt
|
||||
MIIBOTCB5qADAgECAgEAMAsGCSqGSIb3DQEBBTAAMB4XDTcwMDEwMTAwMDAwMFoX
|
||||
DTQ5MTIzMTIzNTk1OVowADBaMAsGCSqGSIb3DQEBAQNLADBIAkEAsuA5mAFMj6Q7
|
||||
qoBzcvKzIq4kzuT5epSp2AkcQfyBHm7K13Ws7u+0b5Vb9gqTf5cAiIKcrtrXVqkL
|
||||
8i1UQF6AzwIDAQABo08wTTAOBgNVHQ8BAf8EBAMCACQwDQYDVR0OBAYEBAECAwQw
|
||||
DwYDVR0jBAgwBoAEAQIDBDAbBgNVHREEFDASggkxMjcuMC4wLjGCBVs6OjFdMAsG
|
||||
CSqGSIb3DQEBBQNBAJH30zjLWRztrWpOCgJL8RQWLaKzhK79pVhAx6q/3NrF16C7
|
||||
+l1BRZstTwIGdoGId8BRpErK1TXkniFb95ZMynM=
|
||||
-----END CERTIFICATE-----
|
||||
`)
|
||||
|
||||
// localhostKey is the private key for localhostCert.
|
||||
var localhostKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIBkgIBAQKCAIB6oy4iT42G6qk+GGn5VL5JlnJT6ZG5cqaMNFaNGlIxNb6CPUZL
|
||||
Kq2sM3gRaimsktIwnNAcNwQGHpe1tZo+J/Pl04JTt71Y/TTAxy7OX27aZf1Rpt0S
|
||||
jdZ7vTPnFDPNsHGeKBKvPt55l2+YKjkZmV7eRevsVbpkNvNGB+T5d4Ge/wIBAwKC
|
||||
AIBRwh7Bil5Z8cYpZZv7jdQxDvbim7Z7ocRdeDmzZuF2I9RW04QyHHPIIlALnBvI
|
||||
YeF1veASz1gEFGUjzmbUGqKYSbCoTzXoev+F4bmbRxcX9sOmtslqvhMSHRSzA5NH
|
||||
aDVI3Hn4wvBVD8gePu8ACWqvPGbCiql11OKCMfjlPn2uuwJAx/24/F5DjXZ6hQQ7
|
||||
HxScOxKrpx5WnA9r1wZTltOTZkhRRzuLc21WJeE3M15QUdWi3zZxCKRFoth65HEs
|
||||
jy9YHQJAnPueRI44tz79b5QqVbeaOMUr7ZCb1Kp0uo6G+ANPLdlfliAupwij2eIz
|
||||
mHRJOWk0jBtXfRft1McH2H51CpXAyw==
|
||||
MIIBPQIBAAJBALLgOZgBTI+kO6qAc3LysyKuJM7k+XqUqdgJHEH8gR5uytd1rO7v
|
||||
tG+VW/YKk3+XAIiCnK7a11apC/ItVEBegM8CAwEAAQJBAI5sxq7naeR9ahyqRkJi
|
||||
SIv2iMxLuPEHaezf5CYOPWjSjBPyVhyRevkhtqEjF/WkgL7C2nWpYHsUcBDBQVF0
|
||||
3KECIQDtEGB2ulnkZAahl3WuJziXGLB+p8Wgx7wzSM6bHu1c6QIhAMEp++CaS+SJ
|
||||
/TrU0zwY/fW4SvQeb49BPZUF3oqR8Xz3AiEA1rAJHBzBgdOQKdE3ksMUPcnvNJSN
|
||||
poCcELmz2clVXtkCIQCLytuLV38XHToTipR4yMl6O+6arzAjZ56uq7m7ZRV0TwIh
|
||||
AM65XAOw8Dsg9Kq78aYXiOEDc5DL0sbFUu/SlmRcCg93
|
||||
-----END RSA PRIVATE KEY-----
|
||||
`)
|
||||
|
Loading…
Reference in New Issue
Block a user