mirror of
https://github.com/golang/go
synced 2024-11-21 20:44:39 -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
|
TARG=crypto/x509
|
||||||
GOFILES=\
|
GOFILES=\
|
||||||
cert_pool.go\
|
cert_pool.go\
|
||||||
|
pkcs1.go\
|
||||||
verify.go\
|
verify.go\
|
||||||
x509.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"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// pkcs1PrivateKey is a structure which mirrors the PKCS#1 ASN.1 for an RSA private key.
|
// pkixPublicKey reflects a PKIX public key structure. See SubjectPublicKeyInfo
|
||||||
type pkcs1PrivateKey struct {
|
// in RFC 3280.
|
||||||
Version int
|
type pkixPublicKey struct {
|
||||||
N *big.Int
|
Algo pkix.AlgorithmIdentifier
|
||||||
E int
|
BitString asn1.BitString
|
||||||
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 {
|
// ParsePKIXPublicKey parses a DER encoded public key. These values are
|
||||||
Prime *big.Int
|
// typically found in PEM blocks with "BEGIN PUBLIC KEY".
|
||||||
|
func ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err os.Error) {
|
||||||
// We ignore these values because rsa will calculate them.
|
var pki publicKeyInfo
|
||||||
Exp *big.Int
|
if _, err = asn1.Unmarshal(derBytes, &pki); err != nil {
|
||||||
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
|
return
|
||||||
}
|
}
|
||||||
if err != nil {
|
algo := getPublicKeyAlgorithmFromOID(pki.Algorithm.Algorithm)
|
||||||
return
|
if algo == UnknownPublicKeyAlgorithm {
|
||||||
|
return nil, os.NewError("ParsePKIXPublicKey: unknown public key algorithm")
|
||||||
}
|
}
|
||||||
|
return parsePublicKey(algo, &pki)
|
||||||
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.
|
// MarshalPKIXPublicKey serialises a public key to DER-encoded PKIX format.
|
||||||
func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte {
|
func MarshalPKIXPublicKey(pub interface{}) ([]byte, os.Error) {
|
||||||
key.Precompute()
|
var pubBytes []byte
|
||||||
|
|
||||||
version := 0
|
switch pub := pub.(type) {
|
||||||
if len(key.Primes) > 2 {
|
case *rsa.PublicKey:
|
||||||
version = 1
|
pubBytes, _ = asn1.Marshal(rsaPublicKey{
|
||||||
|
N: pub.N,
|
||||||
|
E: pub.E,
|
||||||
|
})
|
||||||
|
default:
|
||||||
|
return nil, os.NewError("MarshalPKIXPublicKey: unknown public key type")
|
||||||
}
|
}
|
||||||
|
|
||||||
priv := pkcs1PrivateKey{
|
pkix := pkixPublicKey{
|
||||||
Version: version,
|
Algo: pkix.AlgorithmIdentifier{
|
||||||
N: key.N,
|
Algorithm: []int{1, 2, 840, 113549, 1, 1, 1},
|
||||||
E: key.PublicKey.E,
|
// This is a NULL parameters value which is technically
|
||||||
D: key.D,
|
// superfluous, but most other code includes it and, by
|
||||||
P: key.Primes[0],
|
// doing this, we match their public key hashes.
|
||||||
Q: key.Primes[1],
|
Parameters: asn1.RawValue{
|
||||||
Dp: key.Precomputed.Dp,
|
Tag: 5,
|
||||||
Dq: key.Precomputed.Dq,
|
},
|
||||||
Qinv: key.Precomputed.Qinv,
|
},
|
||||||
|
BitString: asn1.BitString{
|
||||||
|
Bytes: pubBytes,
|
||||||
|
BitLength: 8 * len(pubBytes),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
priv.AdditionalPrimes = make([]pkcs1AdditionalRSAPrime, len(key.Precomputed.CRTValues))
|
ret, _ := asn1.Marshal(pkix)
|
||||||
for i, values := range key.Precomputed.CRTValues {
|
return ret, nil
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// These structures reflect the ASN.1 structure of X.509 certificates.:
|
// These structures reflect the ASN.1 structure of X.509 certificates.:
|
||||||
@ -485,11 +436,6 @@ type basicConstraints struct {
|
|||||||
MaxPathLen int `asn1:"optional"`
|
MaxPathLen int `asn1:"optional"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type rsaPublicKey struct {
|
|
||||||
N *big.Int
|
|
||||||
E int
|
|
||||||
}
|
|
||||||
|
|
||||||
// RFC 5280 4.2.1.4
|
// RFC 5280 4.2.1.4
|
||||||
type policyInformation struct {
|
type policyInformation struct {
|
||||||
Policy asn1.ObjectIdentifier
|
Policy asn1.ObjectIdentifier
|
||||||
|
@ -6,6 +6,7 @@ package x509
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"asn1"
|
"asn1"
|
||||||
|
"bytes"
|
||||||
"big"
|
"big"
|
||||||
"crypto/dsa"
|
"crypto/dsa"
|
||||||
"crypto/rand"
|
"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-----
|
var pemPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
|
||||||
MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
|
MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
|
||||||
fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
|
fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
|
||||||
|
Loading…
Reference in New Issue
Block a user