mirror of
https://github.com/golang/go
synced 2024-11-21 13:44:45 -07:00
crypto/x509: add code for dealing with PKIX public keys.
We also have functions for dealing with PKCS#1 private keys. This change adds functions for PKIX /public/ keys. Most of the time one won't be parsing them because they usually come in certificates, but marshaling them happens and I've previously copied the code from x509.go for this. R=bradfitz, rsc CC=golang-dev https://golang.org/cl/5286042
This commit is contained in:
parent
e74dcbeb0f
commit
b3812bf6db
@ -7,6 +7,7 @@ include ../../../Make.inc
|
||||
TARG=crypto/x509
|
||||
GOFILES=\
|
||||
cert_pool.go\
|
||||
pkcs1.go\
|
||||
verify.go\
|
||||
x509.go\
|
||||
|
||||
|
122
src/pkg/crypto/x509/pkcs1.go
Normal file
122
src/pkg/crypto/x509/pkcs1.go
Normal file
@ -0,0 +1,122 @@
|
||||
// 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 x509
|
||||
|
||||
import (
|
||||
"asn1"
|
||||
"big"
|
||||
"os"
|
||||
"crypto/rsa"
|
||||
)
|
||||
|
||||
// pkcs1PrivateKey is a structure which mirrors the PKCS#1 ASN.1 for an RSA private key.
|
||||
type pkcs1PrivateKey struct {
|
||||
Version int
|
||||
N *big.Int
|
||||
E int
|
||||
D *big.Int
|
||||
P *big.Int
|
||||
Q *big.Int
|
||||
// We ignore these values, if present, because rsa will calculate them.
|
||||
Dp *big.Int `asn1:"optional"`
|
||||
Dq *big.Int `asn1:"optional"`
|
||||
Qinv *big.Int `asn1:"optional"`
|
||||
|
||||
AdditionalPrimes []pkcs1AdditionalRSAPrime `asn1:"optional"`
|
||||
}
|
||||
|
||||
type pkcs1AdditionalRSAPrime struct {
|
||||
Prime *big.Int
|
||||
|
||||
// We ignore these values because rsa will calculate them.
|
||||
Exp *big.Int
|
||||
Coeff *big.Int
|
||||
}
|
||||
|
||||
// ParsePKCS1PrivateKey returns an RSA private key from its ASN.1 PKCS#1 DER encoded form.
|
||||
func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err os.Error) {
|
||||
var priv pkcs1PrivateKey
|
||||
rest, err := asn1.Unmarshal(der, &priv)
|
||||
if len(rest) > 0 {
|
||||
err = asn1.SyntaxError{"trailing data"}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if priv.Version > 1 {
|
||||
return nil, os.NewError("x509: unsupported private key version")
|
||||
}
|
||||
|
||||
if priv.N.Sign() <= 0 || priv.D.Sign() <= 0 || priv.P.Sign() <= 0 || priv.Q.Sign() <= 0 {
|
||||
return nil, os.NewError("private key contains zero or negative value")
|
||||
}
|
||||
|
||||
key = new(rsa.PrivateKey)
|
||||
key.PublicKey = rsa.PublicKey{
|
||||
E: priv.E,
|
||||
N: priv.N,
|
||||
}
|
||||
|
||||
key.D = priv.D
|
||||
key.Primes = make([]*big.Int, 2+len(priv.AdditionalPrimes))
|
||||
key.Primes[0] = priv.P
|
||||
key.Primes[1] = priv.Q
|
||||
for i, a := range priv.AdditionalPrimes {
|
||||
if a.Prime.Sign() <= 0 {
|
||||
return nil, os.NewError("private key contains zero or negative prime")
|
||||
}
|
||||
key.Primes[i+2] = a.Prime
|
||||
// We ignore the other two values because rsa will calculate
|
||||
// them as needed.
|
||||
}
|
||||
|
||||
err = key.Validate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key.Precompute()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// MarshalPKCS1PrivateKey converts a private key to ASN.1 DER encoded form.
|
||||
func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte {
|
||||
key.Precompute()
|
||||
|
||||
version := 0
|
||||
if len(key.Primes) > 2 {
|
||||
version = 1
|
||||
}
|
||||
|
||||
priv := pkcs1PrivateKey{
|
||||
Version: version,
|
||||
N: key.N,
|
||||
E: key.PublicKey.E,
|
||||
D: key.D,
|
||||
P: key.Primes[0],
|
||||
Q: key.Primes[1],
|
||||
Dp: key.Precomputed.Dp,
|
||||
Dq: key.Precomputed.Dq,
|
||||
Qinv: key.Precomputed.Qinv,
|
||||
}
|
||||
|
||||
priv.AdditionalPrimes = make([]pkcs1AdditionalRSAPrime, len(key.Precomputed.CRTValues))
|
||||
for i, values := range key.Precomputed.CRTValues {
|
||||
priv.AdditionalPrimes[i].Prime = key.Primes[2+i]
|
||||
priv.AdditionalPrimes[i].Exp = values.Exp
|
||||
priv.AdditionalPrimes[i].Coeff = values.Coeff
|
||||
}
|
||||
|
||||
b, _ := asn1.Marshal(priv)
|
||||
return b
|
||||
}
|
||||
|
||||
// rsaPublicKey reflects the ASN.1 structure of a PKCS#1 public key.
|
||||
type rsaPublicKey struct {
|
||||
N *big.Int
|
||||
E int
|
||||
}
|
@ -20,108 +20,59 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// pkcs1PrivateKey is a structure which mirrors the PKCS#1 ASN.1 for an RSA private key.
|
||||
type pkcs1PrivateKey struct {
|
||||
Version int
|
||||
N *big.Int
|
||||
E int
|
||||
D *big.Int
|
||||
P *big.Int
|
||||
Q *big.Int
|
||||
// We ignore these values, if present, because rsa will calculate them.
|
||||
Dp *big.Int `asn1:"optional"`
|
||||
Dq *big.Int `asn1:"optional"`
|
||||
Qinv *big.Int `asn1:"optional"`
|
||||
|
||||
AdditionalPrimes []pkcs1AdditionalRSAPrime `asn1:"optional"`
|
||||
// pkixPublicKey reflects a PKIX public key structure. See SubjectPublicKeyInfo
|
||||
// in RFC 3280.
|
||||
type pkixPublicKey struct {
|
||||
Algo pkix.AlgorithmIdentifier
|
||||
BitString asn1.BitString
|
||||
}
|
||||
|
||||
type pkcs1AdditionalRSAPrime struct {
|
||||
Prime *big.Int
|
||||
|
||||
// We ignore these values because rsa will calculate them.
|
||||
Exp *big.Int
|
||||
Coeff *big.Int
|
||||
}
|
||||
|
||||
// ParsePKCS1PrivateKey returns an RSA private key from its ASN.1 PKCS#1 DER encoded form.
|
||||
func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err os.Error) {
|
||||
var priv pkcs1PrivateKey
|
||||
rest, err := asn1.Unmarshal(der, &priv)
|
||||
if len(rest) > 0 {
|
||||
err = asn1.SyntaxError{"trailing data"}
|
||||
// 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 os.Error) {
|
||||
var pki publicKeyInfo
|
||||
if _, err = asn1.Unmarshal(derBytes, &pki); err != nil {
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
algo := getPublicKeyAlgorithmFromOID(pki.Algorithm.Algorithm)
|
||||
if algo == UnknownPublicKeyAlgorithm {
|
||||
return nil, os.NewError("ParsePKIXPublicKey: unknown public key algorithm")
|
||||
}
|
||||
|
||||
if priv.Version > 1 {
|
||||
return nil, os.NewError("x509: unsupported private key version")
|
||||
}
|
||||
|
||||
if priv.N.Sign() <= 0 || priv.D.Sign() <= 0 || priv.P.Sign() <= 0 || priv.Q.Sign() <= 0 {
|
||||
return nil, os.NewError("private key contains zero or negative value")
|
||||
}
|
||||
|
||||
key = new(rsa.PrivateKey)
|
||||
key.PublicKey = rsa.PublicKey{
|
||||
E: priv.E,
|
||||
N: priv.N,
|
||||
}
|
||||
|
||||
key.D = priv.D
|
||||
key.Primes = make([]*big.Int, 2+len(priv.AdditionalPrimes))
|
||||
key.Primes[0] = priv.P
|
||||
key.Primes[1] = priv.Q
|
||||
for i, a := range priv.AdditionalPrimes {
|
||||
if a.Prime.Sign() <= 0 {
|
||||
return nil, os.NewError("private key contains zero or negative prime")
|
||||
}
|
||||
key.Primes[i+2] = a.Prime
|
||||
// We ignore the other two values because rsa will calculate
|
||||
// them as needed.
|
||||
}
|
||||
|
||||
err = key.Validate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key.Precompute()
|
||||
|
||||
return
|
||||
return parsePublicKey(algo, &pki)
|
||||
}
|
||||
|
||||
// MarshalPKCS1PrivateKey converts a private key to ASN.1 DER encoded form.
|
||||
func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte {
|
||||
key.Precompute()
|
||||
// MarshalPKIXPublicKey serialises a public key to DER-encoded PKIX format.
|
||||
func MarshalPKIXPublicKey(pub interface{}) ([]byte, os.Error) {
|
||||
var pubBytes []byte
|
||||
|
||||
version := 0
|
||||
if len(key.Primes) > 2 {
|
||||
version = 1
|
||||
switch pub := pub.(type) {
|
||||
case *rsa.PublicKey:
|
||||
pubBytes, _ = asn1.Marshal(rsaPublicKey{
|
||||
N: pub.N,
|
||||
E: pub.E,
|
||||
})
|
||||
default:
|
||||
return nil, os.NewError("MarshalPKIXPublicKey: unknown public key type")
|
||||
}
|
||||
|
||||
priv := pkcs1PrivateKey{
|
||||
Version: version,
|
||||
N: key.N,
|
||||
E: key.PublicKey.E,
|
||||
D: key.D,
|
||||
P: key.Primes[0],
|
||||
Q: key.Primes[1],
|
||||
Dp: key.Precomputed.Dp,
|
||||
Dq: key.Precomputed.Dq,
|
||||
Qinv: key.Precomputed.Qinv,
|
||||
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),
|
||||
},
|
||||
}
|
||||
|
||||
priv.AdditionalPrimes = make([]pkcs1AdditionalRSAPrime, len(key.Precomputed.CRTValues))
|
||||
for i, values := range key.Precomputed.CRTValues {
|
||||
priv.AdditionalPrimes[i].Prime = key.Primes[2+i]
|
||||
priv.AdditionalPrimes[i].Exp = values.Exp
|
||||
priv.AdditionalPrimes[i].Coeff = values.Coeff
|
||||
}
|
||||
|
||||
b, _ := asn1.Marshal(priv)
|
||||
return b
|
||||
ret, _ := asn1.Marshal(pkix)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// These structures reflect the ASN.1 structure of X.509 certificates.:
|
||||
@ -485,11 +436,6 @@ type basicConstraints struct {
|
||||
MaxPathLen int `asn1:"optional"`
|
||||
}
|
||||
|
||||
type rsaPublicKey struct {
|
||||
N *big.Int
|
||||
E int
|
||||
}
|
||||
|
||||
// RFC 5280 4.2.1.4
|
||||
type policyInformation struct {
|
||||
Policy asn1.ObjectIdentifier
|
||||
|
@ -6,6 +6,7 @@ package x509
|
||||
|
||||
import (
|
||||
"asn1"
|
||||
"bytes"
|
||||
"big"
|
||||
"crypto/dsa"
|
||||
"crypto/rand"
|
||||
@ -34,6 +35,40 @@ func TestParsePKCS1PrivateKey(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsePKIXPublicKey(t *testing.T) {
|
||||
block, _ := pem.Decode([]byte(pemPublicKey))
|
||||
pub, err := ParsePKIXPublicKey(block.Bytes)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to parse RSA public key: %s", err)
|
||||
return
|
||||
}
|
||||
rsaPub, ok := pub.(*rsa.PublicKey)
|
||||
if !ok {
|
||||
t.Errorf("Value returned from ParsePKIXPublicKey was not an RSA public key")
|
||||
return
|
||||
}
|
||||
|
||||
pubBytes2, err := MarshalPKIXPublicKey(rsaPub)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to marshal RSA public key for the second time: %s", err)
|
||||
return
|
||||
}
|
||||
if !bytes.Equal(pubBytes2, block.Bytes) {
|
||||
t.Errorf("Reserialization of public key didn't match. got %x, want %x", pubBytes2, block.Bytes)
|
||||
}
|
||||
}
|
||||
|
||||
var pemPublicKey = `-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3VoPN9PKUjKFLMwOge6+
|
||||
wnDi8sbETGIx2FKXGgqtAKpzmem53kRGEQg8WeqRmp12wgp74TGpkEXsGae7RS1k
|
||||
enJCnma4fii+noGH7R0qKgHvPrI2Bwa9hzsH8tHxpyM3qrXslOmD45EH9SxIDUBJ
|
||||
FehNdaPbLP1gFyahKMsdfxFJLUvbUycuZSJ2ZnIgeVxwm4qbSvZInL9Iu4FzuPtg
|
||||
fINKcbbovy1qq4KvPIrXzhbY3PWDc6btxCf3SE0JdE1MCPThntB62/bLMSQ7xdDR
|
||||
FF53oIpvxe/SCOymfWq/LW849Ytv3Xwod0+wzAP8STXG4HSELS4UedPYeHJJJYcZ
|
||||
+QIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
`
|
||||
|
||||
var pemPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
|
||||
fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
|
||||
|
Loading…
Reference in New Issue
Block a user