-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
*Partially* revert "Remove now-unneeded PKCS8 code and update certuti…
…l tests for Go 1.10" This partially reverts commit 83f6b21.
- Loading branch information
Showing
4 changed files
with
237 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
// 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 certutil | ||
|
||
import ( | ||
"crypto/ecdsa" | ||
"crypto/elliptic" | ||
"crypto/rsa" | ||
"crypto/x509" | ||
"crypto/x509/pkix" | ||
"encoding/asn1" | ||
"errors" | ||
"fmt" | ||
) | ||
|
||
var ( | ||
oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33} | ||
oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7} | ||
oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34} | ||
oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35} | ||
|
||
oidPublicKeyRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1} | ||
oidPublicKeyDSA = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1} | ||
oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1} | ||
) | ||
|
||
// pkcs8 reflects an ASN.1, PKCS#8 PrivateKey. See | ||
// ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-8/pkcs-8v1_2.asn | ||
// and RFC 5208. | ||
type pkcs8 struct { | ||
Version int | ||
Algo pkix.AlgorithmIdentifier | ||
PrivateKey []byte | ||
// optional attributes omitted. | ||
} | ||
|
||
type ecPrivateKey struct { | ||
Version int | ||
PrivateKey []byte | ||
NamedCurveOID asn1.ObjectIdentifier `asn1:"optional,explicit,tag:0"` | ||
PublicKey asn1.BitString `asn1:"optional,explicit,tag:1"` | ||
} | ||
|
||
// MarshalPKCS8PrivateKey converts a private key to PKCS#8 encoded form. | ||
// The following key types are supported: *rsa.PrivateKey, *ecdsa.PublicKey. | ||
// Unsupported key types result in an error. | ||
// | ||
// See RFC 5208. | ||
func MarshalPKCS8PrivateKey(key interface{}) ([]byte, error) { | ||
var privKey pkcs8 | ||
|
||
switch k := key.(type) { | ||
case *rsa.PrivateKey: | ||
privKey.Algo = pkix.AlgorithmIdentifier{ | ||
Algorithm: oidPublicKeyRSA, | ||
Parameters: asn1.NullRawValue, | ||
} | ||
privKey.PrivateKey = x509.MarshalPKCS1PrivateKey(k) | ||
|
||
case *ecdsa.PrivateKey: | ||
oid, ok := oidFromNamedCurve(k.Curve) | ||
if !ok { | ||
return nil, errors.New("x509: unknown curve while marshalling to PKCS#8") | ||
} | ||
|
||
oidBytes, err := asn1.Marshal(oid) | ||
if err != nil { | ||
return nil, errors.New("x509: failed to marshal curve OID: " + err.Error()) | ||
} | ||
|
||
privKey.Algo = pkix.AlgorithmIdentifier{ | ||
Algorithm: oidPublicKeyECDSA, | ||
Parameters: asn1.RawValue{ | ||
FullBytes: oidBytes, | ||
}, | ||
} | ||
|
||
if privKey.PrivateKey, err = marshalECPrivateKeyWithOID(k, nil); err != nil { | ||
return nil, errors.New("x509: failed to marshal EC private key while building PKCS#8: " + err.Error()) | ||
} | ||
|
||
default: | ||
return nil, fmt.Errorf("x509: unknown key type while marshalling PKCS#8: %T", key) | ||
} | ||
|
||
return asn1.Marshal(privKey) | ||
} | ||
|
||
func oidFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) { | ||
switch curve { | ||
case elliptic.P224(): | ||
return oidNamedCurveP224, true | ||
case elliptic.P256(): | ||
return oidNamedCurveP256, true | ||
case elliptic.P384(): | ||
return oidNamedCurveP384, true | ||
case elliptic.P521(): | ||
return oidNamedCurveP521, true | ||
} | ||
|
||
return nil, false | ||
} | ||
|
||
// marshalECPrivateKey marshals an EC private key into ASN.1, DER format and | ||
// sets the curve ID to the given OID, or omits it if OID is nil. | ||
func marshalECPrivateKeyWithOID(key *ecdsa.PrivateKey, oid asn1.ObjectIdentifier) ([]byte, error) { | ||
privateKeyBytes := key.D.Bytes() | ||
paddedPrivateKey := make([]byte, (key.Curve.Params().N.BitLen()+7)/8) | ||
copy(paddedPrivateKey[len(paddedPrivateKey)-len(privateKeyBytes):], privateKeyBytes) | ||
|
||
return asn1.Marshal(ecPrivateKey{ | ||
Version: 1, | ||
PrivateKey: paddedPrivateKey, | ||
NamedCurveOID: oid, | ||
PublicKey: asn1.BitString{Bytes: elliptic.Marshal(key.Curve, key.X, key.Y)}, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
// 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 certutil | ||
|
||
import ( | ||
"bytes" | ||
"crypto/ecdsa" | ||
"crypto/elliptic" | ||
"crypto/rsa" | ||
"crypto/x509" | ||
"encoding/hex" | ||
"reflect" | ||
"testing" | ||
) | ||
|
||
// Generated using: | ||
// openssl genrsa 1024 | openssl pkcs8 -topk8 -nocrypt | ||
var pkcs8RSAPrivateKeyHex = `30820278020100300d06092a864886f70d0101010500048202623082025e02010002818100cfb1b5bf9685ffa97b4f99df4ff122b70e59ac9b992f3bc2b3dde17d53c1a34928719b02e8fd17839499bfbd515bd6ef99c7a1c47a239718fe36bfd824c0d96060084b5f67f0273443007a24dfaf5634f7772c9346e10eb294c2306671a5a5e719ae24b4de467291bc571014b0e02dec04534d66a9bb171d644b66b091780e8d020301000102818100b595778383c4afdbab95d2bfed12b3f93bb0a73a7ad952f44d7185fd9ec6c34de8f03a48770f2009c8580bcd275e9632714e9a5e3f32f29dc55474b2329ff0ebc08b3ffcb35bc96e6516b483df80a4a59cceb71918cbabf91564e64a39d7e35dce21cb3031824fdbc845dba6458852ec16af5dddf51a8397a8797ae0337b1439024100ea0eb1b914158c70db39031dd8904d6f18f408c85fbbc592d7d20dee7986969efbda081fdf8bc40e1b1336d6b638110c836bfdc3f314560d2e49cd4fbde1e20b024100e32a4e793b574c9c4a94c8803db5152141e72d03de64e54ef2c8ed104988ca780cd11397bc359630d01b97ebd87067c5451ba777cf045ca23f5912f1031308c702406dfcdbbd5a57c9f85abc4edf9e9e29153507b07ce0a7ef6f52e60dcfebe1b8341babd8b789a837485da6c8d55b29bbb142ace3c24a1f5b54b454d01b51e2ad03024100bd6a2b60dee01e1b3bfcef6a2f09ed027c273cdbbaf6ba55a80f6dcc64e4509ee560f84b4f3e076bd03b11e42fe71a3fdd2dffe7e0902c8584f8cad877cdc945024100aa512fa4ada69881f1d8bb8ad6614f192b83200aef5edf4811313d5ef30a86cbd0a90f7b025c71ea06ec6b34db6306c86b1040670fd8654ad7291d066d06d031` | ||
|
||
// Generated using: | ||
// openssl ecparam -genkey -name secp224r1 | openssl pkcs8 -topk8 -nocrypt | ||
var pkcs8P224PrivateKeyHex = `3078020100301006072a8648ce3d020106052b810400210461305f020101041cca3d72b3e88fed2684576dad9b80a9180363a5424986900e3abcab3fa13c033a0004f8f2a6372872a4e61263ed893afb919576a4cacfecd6c081a2cbc76873cf4ba8530703c6042b3a00e2205087e87d2435d2e339e25702fae1` | ||
|
||
// Generated using: | ||
// openssl ecparam -genkey -name secp256r1 | openssl pkcs8 -topk8 -nocrypt | ||
var pkcs8P256PrivateKeyHex = `308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b0201010420dad6b2f49ca774c36d8ae9517e935226f667c929498f0343d2424d0b9b591b43a14403420004b9c9b90095476afe7b860d8bd43568cab7bcb2eed7b8bf2fa0ce1762dd20b04193f859d2d782b1e4cbfd48492f1f533113a6804903f292258513837f07fda735` | ||
|
||
// Generated using: | ||
// openssl ecparam -genkey -name secp384r1 | openssl pkcs8 -topk8 -nocrypt | ||
var pkcs8P384PrivateKeyHex = `3081b6020100301006072a8648ce3d020106052b8104002204819e30819b02010104309bf832f6aaaeacb78ce47ffb15e6fd0fd48683ae79df6eca39bfb8e33829ac94aa29d08911568684c2264a08a4ceb679a164036200049070ad4ed993c7770d700e9f6dc2baa83f63dd165b5507f98e8ff29b5d2e78ccbe05c8ddc955dbf0f7497e8222cfa49314fe4e269459f8e880147f70d785e530f2939e4bf9f838325bb1a80ad4cf59272ae0e5efe9a9dc33d874492596304bd3` | ||
|
||
// Generated using: | ||
// openssl ecparam -genkey -name secp521r1 | openssl pkcs8 -topk8 -nocrypt | ||
// | ||
// Note that OpenSSL will truncate the private key if it can (i.e. it emits it | ||
// like an integer, even though it's an OCTET STRING field). Thus if you | ||
// regenerate this you may, randomly, find that it's a byte shorter than | ||
// expected and the Go test will fail to recreate it exactly. | ||
var pkcs8P521PrivateKeyHex = `3081ee020100301006072a8648ce3d020106052b810400230481d63081d3020101044200cfe0b87113a205cf291bb9a8cd1a74ac6c7b2ebb8199aaa9a5010d8b8012276fa3c22ac913369fa61beec2a3b8b4516bc049bde4fb3b745ac11b56ab23ac52e361a1818903818600040138f75acdd03fbafa4f047a8e4b272ba9d555c667962b76f6f232911a5786a0964e5edea6bd21a6f8725720958de049c6e3e6661c1c91b227cebee916c0319ed6ca003db0a3206d372229baf9dd25d868bf81140a518114803ce40c1855074d68c4e9dab9e65efba7064c703b400f1767f217dac82715ac1f6d88c74baf47a7971de4ea` | ||
|
||
func TestPKCS8(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
keyHex string | ||
keyType reflect.Type | ||
curve elliptic.Curve | ||
}{ | ||
{ | ||
name: "RSA private key", | ||
keyHex: pkcs8RSAPrivateKeyHex, | ||
keyType: reflect.TypeOf(&rsa.PrivateKey{}), | ||
}, | ||
{ | ||
name: "P-224 private key", | ||
keyHex: pkcs8P224PrivateKeyHex, | ||
keyType: reflect.TypeOf(&ecdsa.PrivateKey{}), | ||
curve: elliptic.P224(), | ||
}, | ||
{ | ||
name: "P-256 private key", | ||
keyHex: pkcs8P256PrivateKeyHex, | ||
keyType: reflect.TypeOf(&ecdsa.PrivateKey{}), | ||
curve: elliptic.P256(), | ||
}, | ||
{ | ||
name: "P-384 private key", | ||
keyHex: pkcs8P384PrivateKeyHex, | ||
keyType: reflect.TypeOf(&ecdsa.PrivateKey{}), | ||
curve: elliptic.P384(), | ||
}, | ||
{ | ||
name: "P-521 private key", | ||
keyHex: pkcs8P521PrivateKeyHex, | ||
keyType: reflect.TypeOf(&ecdsa.PrivateKey{}), | ||
curve: elliptic.P521(), | ||
}, | ||
} | ||
|
||
for _, test := range tests { | ||
derBytes, err := hex.DecodeString(test.keyHex) | ||
if err != nil { | ||
t.Errorf("%s: failed to decode hex: %s", test.name, err) | ||
continue | ||
} | ||
privKey, err := x509.ParsePKCS8PrivateKey(derBytes) | ||
if err != nil { | ||
t.Errorf("%s: failed to decode PKCS#8: %s", test.name, err) | ||
continue | ||
} | ||
if reflect.TypeOf(privKey) != test.keyType { | ||
t.Errorf("%s: decoded PKCS#8 returned unexpected key type: %T", test.name, privKey) | ||
continue | ||
} | ||
if ecKey, isEC := privKey.(*ecdsa.PrivateKey); isEC && ecKey.Curve != test.curve { | ||
t.Errorf("%s: decoded PKCS#8 returned unexpected curve %#v", test.name, ecKey.Curve) | ||
continue | ||
} | ||
reserialised, err := MarshalPKCS8PrivateKey(privKey) | ||
if err != nil { | ||
t.Errorf("%s: failed to marshal into PKCS#8: %s", test.name, err) | ||
continue | ||
} | ||
if !bytes.Equal(derBytes, reserialised) { | ||
t.Errorf("%s: marshalled PKCS#8 didn't match original: got %x, want %x", test.name, reserialised, derBytes) | ||
continue | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters