diff options
Diffstat (limited to 'libgo/go/crypto/x509')
-rw-r--r-- | libgo/go/crypto/x509/cert_pool.go | 2 | ||||
-rw-r--r-- | libgo/go/crypto/x509/pem_decrypt.go | 156 | ||||
-rw-r--r-- | libgo/go/crypto/x509/pem_decrypt_test.go | 124 | ||||
-rw-r--r-- | libgo/go/crypto/x509/pkcs8.go | 20 | ||||
-rw-r--r-- | libgo/go/crypto/x509/pkcs8_test.go | 18 | ||||
-rw-r--r-- | libgo/go/crypto/x509/sec1.go | 69 | ||||
-rw-r--r-- | libgo/go/crypto/x509/sec1_test.go | 22 | ||||
-rw-r--r-- | libgo/go/crypto/x509/x509.go | 18 |
8 files changed, 373 insertions, 56 deletions
diff --git a/libgo/go/crypto/x509/cert_pool.go b/libgo/go/crypto/x509/cert_pool.go index 616a0b3c1e8..505f4d4f776 100644 --- a/libgo/go/crypto/x509/cert_pool.go +++ b/libgo/go/crypto/x509/cert_pool.go @@ -103,7 +103,7 @@ func (s *CertPool) AppendCertsFromPEM(pemCerts []byte) (ok bool) { } // Subjects returns a list of the DER-encoded subjects of -// all of the certificates in the pool. +// all of the certificates in the pool. func (s *CertPool) Subjects() (res [][]byte) { res = make([][]byte, len(s.certs)) for i, c := range s.certs { diff --git a/libgo/go/crypto/x509/pem_decrypt.go b/libgo/go/crypto/x509/pem_decrypt.go index 21f62e5d76b..194c81bf688 100644 --- a/libgo/go/crypto/x509/pem_decrypt.go +++ b/libgo/go/crypto/x509/pem_decrypt.go @@ -16,13 +16,64 @@ import ( "encoding/hex" "encoding/pem" "errors" + "io" "strings" ) -// rfc1423Algos represents how to create a block cipher for a decryption mode. +type PEMCipher int + +// Possible values for the EncryptPEMBlock encryption algorithm. +const ( + _ PEMCipher = iota + PEMCipherDES + PEMCipher3DES + PEMCipherAES128 + PEMCipherAES192 + PEMCipherAES256 +) + +// rfc1423Algo holds a method for enciphering a PEM block. type rfc1423Algo struct { - cipherFunc func([]byte) (cipher.Block, error) + cipher PEMCipher + name string + cipherFunc func(key []byte) (cipher.Block, error) keySize int + blockSize int +} + +// rfc1423Algos holds a slice of the possible ways to encrypt a PEM +// block. The ivSize numbers were taken from the OpenSSL source. +var rfc1423Algos = []rfc1423Algo{{ + cipher: PEMCipherDES, + name: "DES-CBC", + cipherFunc: des.NewCipher, + keySize: 8, + blockSize: des.BlockSize, +}, { + cipher: PEMCipher3DES, + name: "DES-EDE3-CBC", + cipherFunc: des.NewTripleDESCipher, + keySize: 24, + blockSize: des.BlockSize, +}, { + cipher: PEMCipherAES128, + name: "AES-128-CBC", + cipherFunc: aes.NewCipher, + keySize: 16, + blockSize: aes.BlockSize, +}, { + cipher: PEMCipherAES192, + name: "AES-192-CBC", + cipherFunc: aes.NewCipher, + keySize: 24, + blockSize: aes.BlockSize, +}, { + cipher: PEMCipherAES256, + name: "AES-256-CBC", + cipherFunc: aes.NewCipher, + keySize: 32, + blockSize: aes.BlockSize, +}, } // deriveKey uses a key derivation function to stretch the password into a key @@ -41,20 +92,9 @@ func (c rfc1423Algo) deriveKey(password, salt []byte) []byte { digest = hash.Sum(digest[:0]) copy(out[i:], digest) } - return out } -// rfc1423Algos is a mapping of encryption algorithm to an rfc1423Algo that can -// create block ciphers for that mode. -var rfc1423Algos = map[string]rfc1423Algo{ - "DES-CBC": {des.NewCipher, 8}, - "DES-EDE3-CBC": {des.NewTripleDESCipher, 24}, - "AES-128-CBC": {aes.NewCipher, 16}, - "AES-192-CBC": {aes.NewCipher, 24}, - "AES-256-CBC": {aes.NewCipher, 32}, -} - // IsEncryptedPEMBlock returns if the PEM block is password encrypted. func IsEncryptedPEMBlock(b *pem.Block) bool { _, ok := b.Headers["DEK-Info"] @@ -81,17 +121,16 @@ func DecryptPEMBlock(b *pem.Block, password []byte) ([]byte, error) { } mode, hexIV := dek[:idx], dek[idx+1:] + ciph := cipherByName(mode) + if ciph == nil { + return nil, errors.New("x509: unknown encryption mode") + } iv, err := hex.DecodeString(hexIV) if err != nil { return nil, err } - if len(iv) < 8 { - return nil, errors.New("x509: not enough bytes in IV") - } - - ciph, ok := rfc1423Algos[mode] - if !ok { - return nil, errors.New("x509: unknown encryption mode") + if len(iv) != ciph.blockSize { + return nil, errors.New("x509: incorrect IV size") } // Based on the OpenSSL implementation. The salt is the first 8 bytes @@ -107,27 +146,88 @@ func DecryptPEMBlock(b *pem.Block, password []byte) ([]byte, error) { dec.CryptBlocks(data, b.Bytes) // Blocks are padded using a scheme where the last n bytes of padding are all - // equal to n. It can pad from 1 to 8 bytes inclusive. See RFC 1423. + // equal to n. It can pad from 1 to blocksize bytes inclusive. See RFC 1423. // For example: // [x y z 2 2] // [x y 7 7 7 7 7 7 7] // If we detect a bad padding, we assume it is an invalid password. dlen := len(data) - if dlen == 0 { + if dlen == 0 || dlen%ciph.blockSize != 0 { return nil, errors.New("x509: invalid padding") } - last := data[dlen-1] - if dlen < int(last) { + last := int(data[dlen-1]) + if dlen < last { return nil, IncorrectPasswordError } - if last == 0 || last > 8 { + if last == 0 || last > ciph.blockSize { return nil, IncorrectPasswordError } - for _, val := range data[dlen-int(last):] { - if val != last { + for _, val := range data[dlen-last:] { + if int(val) != last { return nil, IncorrectPasswordError } } + return data[:dlen-last], nil +} + +// EncryptPEMBlock returns a PEM block of the specified type holding the +// given DER-encoded data encrypted with the specified algorithm and +// password. +func EncryptPEMBlock(rand io.Reader, blockType string, data, password []byte, alg PEMCipher) (*pem.Block, error) { + ciph := cipherByKey(alg) + if ciph == nil { + return nil, errors.New("x509: unknown encryption mode") + } + iv := make([]byte, ciph.blockSize) + if _, err := io.ReadFull(rand, iv); err != nil { + return nil, errors.New("x509: cannot generate IV: " + err.Error()) + } + // The salt is the first 8 bytes of the initialization vector, + // matching the key derivation in DecryptPEMBlock. + key := ciph.deriveKey(password, iv[:8]) + block, err := ciph.cipherFunc(key) + if err != nil { + return nil, err + } + enc := cipher.NewCBCEncrypter(block, iv) + pad := ciph.blockSize - len(data)%ciph.blockSize + encrypted := make([]byte, len(data), len(data)+pad) + // We could save this copy by encrypting all the whole blocks in + // the data separately, but it doesn't seem worth the additional + // code. + copy(encrypted, data) + // See RFC 1423, section 1.1 + for i := 0; i < pad; i++ { + encrypted = append(encrypted, byte(pad)) + } + enc.CryptBlocks(encrypted, encrypted) + + return &pem.Block{ + Type: blockType, + Headers: map[string]string{ + "Proc-Type": "4,ENCRYPTED", + "DEK-Info": ciph.name + "," + hex.EncodeToString(iv), + }, + Bytes: encrypted, + }, nil +} + +func cipherByName(name string) *rfc1423Algo { + for i := range rfc1423Algos { + alg := &rfc1423Algos[i] + if alg.name == name { + return alg + } + } + return nil +} - return data[:dlen-int(last)], nil +func cipherByKey(key PEMCipher) *rfc1423Algo { + for i := range rfc1423Algos { + alg := &rfc1423Algos[i] + if alg.cipher == key { + return alg + } + } + return nil } diff --git a/libgo/go/crypto/x509/pem_decrypt_test.go b/libgo/go/crypto/x509/pem_decrypt_test.go index 2cb99836eae..59ba6f90019 100644 --- a/libgo/go/crypto/x509/pem_decrypt_test.go +++ b/libgo/go/crypto/x509/pem_decrypt_test.go @@ -5,34 +5,79 @@ package x509 import ( + "bytes" + "crypto/rand" + "encoding/base64" "encoding/pem" "testing" ) func TestDecrypt(t *testing.T) { - for _, data := range testData { + for i, data := range testData { + t.Logf("test %d. %s", i, data.kind) block, rest := pem.Decode(data.pemData) if len(rest) > 0 { - t.Error(data.kind, "extra data") + t.Error("extra data") } der, err := DecryptPEMBlock(block, data.password) if err != nil { - t.Error(data.kind, err) + t.Error("decrypt failed: ", err) continue } if _, err := ParsePKCS1PrivateKey(der); err != nil { - t.Error(data.kind, "Invalid private key") + t.Error("invalid private key: ", err) + } + plainDER, err := base64.StdEncoding.DecodeString(data.plainDER) + if err != nil { + t.Fatal("cannot decode test DER data: ", err) + } + if !bytes.Equal(der, plainDER) { + t.Error("data mismatch") + } + } +} + +func TestEncrypt(t *testing.T) { + for i, data := range testData { + t.Logf("test %d. %s", i, data.kind) + plainDER, err := base64.StdEncoding.DecodeString(data.plainDER) + if err != nil { + t.Fatal("cannot decode test DER data: ", err) + } + password := []byte("kremvax1") + block, err := EncryptPEMBlock(rand.Reader, "RSA PRIVATE KEY", plainDER, password, data.kind) + if err != nil { + t.Error("encrypt: ", err) + continue + } + if !IsEncryptedPEMBlock(block) { + t.Error("PEM block does not appear to be encrypted") + } + if block.Type != "RSA PRIVATE KEY" { + t.Errorf("unexpected block type; got %q want %q", block.Type, "RSA PRIVATE KEY") + } + if block.Headers["Proc-Type"] != "4,ENCRYPTED" { + t.Errorf("block does not have correct Proc-Type header") + } + der, err := DecryptPEMBlock(block, password) + if err != nil { + t.Error("decrypt: ", err) + continue + } + if !bytes.Equal(der, plainDER) { + t.Errorf("data mismatch") } } } var testData = []struct { - kind string + kind PEMCipher password []byte pemData []byte + plainDER string }{ { - kind: "DES-CBC", + kind: PEMCipherDES, password: []byte("asdf"), pemData: []byte(` -----BEGIN RSA PRIVATE KEY----- @@ -47,9 +92,17 @@ XOH9VfTjb52q/I8Suozq9coVQwg4tXfIoYUdT//O+mB7zJb9HI9Ps77b9TxDE6Gm 4C9brwZ3zg2vqXcwwV6QRZMtyll9rOpxkbw6NPlpfBqkc3xS51bbxivbO/Nve4KD r12ymjFNF4stXCfJnNqKoZ50BHmEEUDu5Wb0fpVn82XrGw7CYc4iug== -----END RSA PRIVATE KEY-----`), + plainDER: ` +MIIBPAIBAAJBAPASZe+tCPU6p80AjHhDkVsLYa51D35e/YGa8QcZyooeZM8EHozo +KD0fNiKI+53bHdy07N+81VQ8/ejPcRoXPlsCAwEAAQJBAMTxIuSq27VpR+zZ7WJf +c6fvv1OBvpMZ0/d1pxL/KnOAgq2rD5hDtk9b0LGhTPgQAmrrMTKuSeGoIuYE+gKQ +QvkCIQD+GC1m+/do+QRurr0uo46Kx1LzLeSCrjBk34wiOp2+dwIhAPHfTLRXS2fv +7rljm0bYa4+eDZpz+E8RcXEgzhhvcQQ9AiAI5eHZJGOyml3MXnQjiPi55WcDOw0w +glcRgT6QCEtz2wIhANSyqaFtosIkHKqrDUGfz/bb5tqMYTAnBruVPaf/WEOBAiEA +9xORWeRG1tRpso4+dYy4KdDkuLPIO01KY6neYGm3BCM=`, }, { - kind: "DES-EDE3-CBC", + kind: PEMCipher3DES, password: []byte("asdf"), pemData: []byte(` -----BEGIN RSA PRIVATE KEY----- @@ -64,9 +117,17 @@ ldw5w7WC7d13x2LsRkwo8ZrDKgIV+Y9GNvhuCCkTzNP0V3gNeJpd201HZHR+9n3w 3z0VjR/MGqsfcy1ziEWMNOO53At3zlG6zP05aHMnMcZoVXadEK6L1gz++inSSDCq gI0UJP4e3JVB7AkgYymYAwiYALAkoEIuanxoc50njJk= -----END RSA PRIVATE KEY-----`), + plainDER: ` +MIIBOwIBAAJBANOCXKdoNS/iP/MAbl9cf1/SF3P+Ns7ZeNL27CfmDh0O6Zduaax5 +NBiumd2PmjkaCu7lQ5JOibHfWn+xJsc3kw0CAwEAAQJANX/W8d1Q/sCqzkuAn4xl +B5a7qfJWaLHndu1QRLNTRJPn0Ee7OKJ4H0QKOhQM6vpjRrz+P2u9thn6wUxoPsef +QQIhAP/jCkfejFcy4v15beqKzwz08/tslVjF+Yq41eJGejmxAiEA05pMoqfkyjcx +fyvGhpoOyoCp71vSGUfR2I9CR65oKh0CIC1Msjs66LlfJtQctRq6bCEtFCxEcsP+ +eEjYo/Sk6WphAiEAxpgWPMJeU/shFT28gS+tmhjPZLpEoT1qkVlC14u0b3ECIQDX +tZZZxCtPAm7shftEib0VU77Lk8MsXJcx2C4voRsjEw==`, }, { - kind: "AES-128-CBC", + kind: PEMCipherAES128, password: []byte("asdf"), pemData: []byte(` -----BEGIN RSA PRIVATE KEY----- @@ -81,9 +142,17 @@ GZbBpf1jDH/pr0iGonuAdl2PCCZUiy+8eLsD2tyviHUkFLOB+ykYoJ5t8ngZ/B6D 080LzLHPCrXKdlr/f50yhNWq08ZxMWQFkui+FDHPDUaEELKAXV8/5PDxw80Rtybo AVYoCVIbZXZCuCO81op8UcOgEpTtyU5Lgh3Mw5scQL0= -----END RSA PRIVATE KEY-----`), + plainDER: ` +MIIBOgIBAAJBAMBlj5FxYtqbcy8wY89d/S7n0+r5MzD9F63BA/Lpl78vQKtdJ5dT +cDGh/rBt1ufRrNp0WihcmZi7Mpl/3jHjiWECAwEAAQJABNOHYnKhtDIqFYj1OAJ3 +k3GlU0OlERmIOoeY/cL2V4lgwllPBEs7r134AY4wMmZSBUj8UR/O4SNO668ElKPE +cQIhAOuqY7/115x5KCdGDMWi+jNaMxIvI4ETGwV40ykGzqlzAiEA0P9oEC3m9tHB +kbpjSTxaNkrXxDgdEOZz8X0uOUUwHNsCIAwzcSCiGLyYJTULUmP1ESERfW1mlV78 +XzzESaJpIM/zAiBQkSTcl9VhcJreQqvjn5BnPZLP4ZHS4gPwJAGdsj5J4QIhAOVR +B3WlRNTXR2WsJ5JdByezg9xzdXzULqmga0OE339a`, }, { - kind: "AES-192-CBC", + kind: PEMCipherAES192, password: []byte("asdf"), pemData: []byte(` -----BEGIN RSA PRIVATE KEY----- @@ -98,9 +167,17 @@ ReUtTw8exmKsY4gsSjhkg5uiw7/ZB1Ihto0qnfQJgjGc680qGkT1d6JfvOfeYAk6 xn5RqS/h8rYAYm64KnepfC9vIujo4NqpaREDmaLdX5MJPQ+SlytITQvgUsUq3q/t Ss85xjQEZH3hzwjQqdJvmA4hYP6SUjxYpBM+02xZ1Xw= -----END RSA PRIVATE KEY-----`), + plainDER: ` +MIIBOwIBAAJBAMGcRrZiNNmtF20zyS6MQ7pdGx17aFDl+lTl+qnLuJRUCMUG05xs +OmxmL/O1Qlf+bnqR8Bgg65SfKg21SYuLhiMCAwEAAQJBAL94uuHyO4wux2VC+qpj +IzPykjdU7XRcDHbbvksf4xokSeUFjjD3PB0Qa83M94y89ZfdILIqS9x5EgSB4/lX +qNkCIQD6cCIqLfzq/lYbZbQgAAjpBXeQVYsbvVtJrPrXJAlVVQIhAMXpDKMeFPMn +J0g2rbx1gngx0qOa5r5iMU5w/noN4W2XAiBjf+WzCG5yFvazD+dOx3TC0A8+4x3P +uZ3pWbaXf5PNuQIgAcdXarvhelH2w2piY1g3BPeFqhzBSCK/yLGxR82KIh8CIQDD ++qGKsd09NhQ/G27y/DARzOYtml1NvdmCQAgsDIIOLA==`, }, { - kind: "AES-256-CBC", + kind: PEMCipherAES256, password: []byte("asdf"), pemData: []byte(` -----BEGIN RSA PRIVATE KEY----- @@ -115,5 +192,32 @@ Pz3RZScwIuubzTGJ1x8EzdffYOsdCa9Mtgpp3L136+23dOd6L/qK2EG2fzrJSHs/ sv5Z/KwlX+3MDEpPQpUwGPlGGdLnjI3UZ+cjgqBcoMiNc6HfgbBgYJSU6aDSHuCk clCwByxWkBNgJ2GrkwNrF26v+bGJJJNR4SKouY1jQf0= -----END RSA PRIVATE KEY-----`), + plainDER: ` +MIIBOgIBAAJBAKy3GFkstoCHIEeUU/qO8207m8WSrjksR+p9B4tf1w5k+2O1V/GY +AQ5WFCApItcOkQe/I0yZZJk/PmCqMzSxrc8CAwEAAQJAOCAz0F7AW9oNelVQSP8F +Sfzx7O1yom+qWyAQQJF/gFR11gpf9xpVnnyu1WxIRnDUh1LZwUsjwlDYb7MB74id +oQIhANPcOiLwOPT4sIUpRM5HG6BF1BI7L77VpyGVk8xNP7X/AiEA0LMHZtk4I+lJ +nClgYp4Yh2JZ1Znbu7IoQMCEJCjwKDECIGd8Dzm5tViTkUW6Hs3Tlf73nNs65duF +aRnSglss8I3pAiEAonEnKruawgD8RavDFR+fUgmQiPz4FnGGeVgfwpGG1JECIBYq +PXHYtPqxQIbD2pScR5qum7iGUh11lEUPkmt+2uqS`, + }, + { + // generated with: + // openssl genrsa -aes128 -passout pass:asdf -out server.orig.key 128 + kind: PEMCipherAES128, + password: []byte("asdf"), + pemData: []byte(` +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-128-CBC,74611ABC2571AF11B1BF9B69E62C89E7 + +6ei/MlytjE0FFgZOGQ+jrwomKfpl8kdefeE0NSt/DMRrw8OacHAzBNi3pPEa0eX3 +eND9l7C9meCirWovjj9QWVHrXyugFuDIqgdhQ8iHTgCfF3lrmcttVrbIfMDw+smD +hTP8O1mS/MHl92NE0nhv0w== +-----END RSA PRIVATE KEY-----`), + plainDER: ` +MGMCAQACEQC6ssxmYuauuHGOCDAI54RdAgMBAAECEQCWIn6Yv2O+kBcDF7STctKB +AgkA8SEfu/2i3g0CCQDGNlXbBHX7kQIIK3Ww5o0cYbECCQDCimPb0dYGsQIIeQ7A +jryIst8=`, }, } diff --git a/libgo/go/crypto/x509/pkcs8.go b/libgo/go/crypto/x509/pkcs8.go index 8c3b65f8078..30caacb3c54 100644 --- a/libgo/go/crypto/x509/pkcs8.go +++ b/libgo/go/crypto/x509/pkcs8.go @@ -11,8 +11,9 @@ import ( "fmt" ) -// pkcs8 reflects an ASN.1, PKCS#8 PrivateKey. See -// ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-8/pkcs-8v1_2.asn. +// pkcs8 reflects an ASN.1, PKCS#8 PrivateKey. See +// ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-8/pkcs-8v1_2.asn +// and RFC5208. type pkcs8 struct { Version int Algo pkix.AlgorithmIdentifier @@ -21,7 +22,7 @@ type pkcs8 struct { } // ParsePKCS8PrivateKey parses an unencrypted, PKCS#8 private key. See -// http://www.rsa.com/rsalabs/node.asp?id=2130 +// http://www.rsa.com/rsalabs/node.asp?id=2130 and RFC5208. func ParsePKCS8PrivateKey(der []byte) (key interface{}, err error) { var privKey pkcs8 if _, err := asn1.Unmarshal(der, &privKey); err != nil { @@ -34,6 +35,19 @@ func ParsePKCS8PrivateKey(der []byte) (key interface{}, err error) { return nil, errors.New("crypto/x509: failed to parse RSA private key embedded in PKCS#8: " + err.Error()) } return key, nil + + case privKey.Algo.Algorithm.Equal(oidPublicKeyECDSA): + bytes := privKey.Algo.Parameters.FullBytes + namedCurveOID := new(asn1.ObjectIdentifier) + if _, err := asn1.Unmarshal(bytes, namedCurveOID); err != nil { + namedCurveOID = nil + } + key, err = parseECPrivateKey(namedCurveOID, privKey.PrivateKey) + if err != nil { + return nil, errors.New("crypto/x509: failed to parse EC private key embedded in PKCS#8: " + err.Error()) + } + return key, nil + default: return nil, fmt.Errorf("crypto/x509: PKCS#8 wrapping contained private key with unknown algorithm: %v", privKey.Algo.Algorithm) } diff --git a/libgo/go/crypto/x509/pkcs8_test.go b/libgo/go/crypto/x509/pkcs8_test.go index 372005f908c..4114efd0e0d 100644 --- a/libgo/go/crypto/x509/pkcs8_test.go +++ b/libgo/go/crypto/x509/pkcs8_test.go @@ -9,12 +9,20 @@ import ( "testing" ) -var pkcs8PrivateKeyHex = `30820278020100300d06092a864886f70d0101010500048202623082025e02010002818100cfb1b5bf9685ffa97b4f99df4ff122b70e59ac9b992f3bc2b3dde17d53c1a34928719b02e8fd17839499bfbd515bd6ef99c7a1c47a239718fe36bfd824c0d96060084b5f67f0273443007a24dfaf5634f7772c9346e10eb294c2306671a5a5e719ae24b4de467291bc571014b0e02dec04534d66a9bb171d644b66b091780e8d020301000102818100b595778383c4afdbab95d2bfed12b3f93bb0a73a7ad952f44d7185fd9ec6c34de8f03a48770f2009c8580bcd275e9632714e9a5e3f32f29dc55474b2329ff0ebc08b3ffcb35bc96e6516b483df80a4a59cceb71918cbabf91564e64a39d7e35dce21cb3031824fdbc845dba6458852ec16af5dddf51a8397a8797ae0337b1439024100ea0eb1b914158c70db39031dd8904d6f18f408c85fbbc592d7d20dee7986969efbda081fdf8bc40e1b1336d6b638110c836bfdc3f314560d2e49cd4fbde1e20b024100e32a4e793b574c9c4a94c8803db5152141e72d03de64e54ef2c8ed104988ca780cd11397bc359630d01b97ebd87067c5451ba777cf045ca23f5912f1031308c702406dfcdbbd5a57c9f85abc4edf9e9e29153507b07ce0a7ef6f52e60dcfebe1b8341babd8b789a837485da6c8d55b29bbb142ace3c24a1f5b54b454d01b51e2ad03024100bd6a2b60dee01e1b3bfcef6a2f09ed027c273cdbbaf6ba55a80f6dcc64e4509ee560f84b4f3e076bd03b11e42fe71a3fdd2dffe7e0902c8584f8cad877cdc945024100aa512fa4ada69881f1d8bb8ad6614f192b83200aef5edf4811313d5ef30a86cbd0a90f7b025c71ea06ec6b34db6306c86b1040670fd8654ad7291d066d06d031` +var pkcs8RSAPrivateKeyHex = `30820278020100300d06092a864886f70d0101010500048202623082025e02010002818100cfb1b5bf9685ffa97b4f99df4ff122b70e59ac9b992f3bc2b3dde17d53c1a34928719b02e8fd17839499bfbd515bd6ef99c7a1c47a239718fe36bfd824c0d96060084b5f67f0273443007a24dfaf5634f7772c9346e10eb294c2306671a5a5e719ae24b4de467291bc571014b0e02dec04534d66a9bb171d644b66b091780e8d020301000102818100b595778383c4afdbab95d2bfed12b3f93bb0a73a7ad952f44d7185fd9ec6c34de8f03a48770f2009c8580bcd275e9632714e9a5e3f32f29dc55474b2329ff0ebc08b3ffcb35bc96e6516b483df80a4a59cceb71918cbabf91564e64a39d7e35dce21cb3031824fdbc845dba6458852ec16af5dddf51a8397a8797ae0337b1439024100ea0eb1b914158c70db39031dd8904d6f18f408c85fbbc592d7d20dee7986969efbda081fdf8bc40e1b1336d6b638110c836bfdc3f314560d2e49cd4fbde1e20b024100e32a4e793b574c9c4a94c8803db5152141e72d03de64e54ef2c8ed104988ca780cd11397bc359630d01b97ebd87067c5451ba777cf045ca23f5912f1031308c702406dfcdbbd5a57c9f85abc4edf9e9e29153507b07ce0a7ef6f52e60dcfebe1b8341babd8b789a837485da6c8d55b29bbb142ace3c24a1f5b54b454d01b51e2ad03024100bd6a2b60dee01e1b3bfcef6a2f09ed027c273cdbbaf6ba55a80f6dcc64e4509ee560f84b4f3e076bd03b11e42fe71a3fdd2dffe7e0902c8584f8cad877cdc945024100aa512fa4ada69881f1d8bb8ad6614f192b83200aef5edf4811313d5ef30a86cbd0a90f7b025c71ea06ec6b34db6306c86b1040670fd8654ad7291d066d06d031` + +// Generated using: +// openssl ecparam -genkey -name secp521r1 | openssl pkcs8 -topk8 -nocrypt +var pkcs8ECPrivateKeyHex = `3081ed020100301006072a8648ce3d020106052b810400230481d53081d20201010441850d81618c5da1aec74c2eed608ba816038506975e6427237c2def150c96a3b13efbfa1f89f1be15cdf4d0ac26422e680e65a0ddd4ad3541ad76165fbf54d6e34ba18189038186000400da97bcedba1eb6d30aeb93c9f9a1454598fa47278df27d6f60ea73eb672d8dc528a9b67885b5b5dcef93c9824f7449ab512ee6a27e76142f56b94b474cfd697e810046c8ca70419365245c1d7d44d0db82c334073835d002232714548abbae6e5700f5ef315ee08b929d8581383dcf2d1c98c2f8a9fccbf79c9579f7b2fd8a90115ac2` func TestPKCS8(t *testing.T) { - derBytes, _ := hex.DecodeString(pkcs8PrivateKeyHex) - _, err := ParsePKCS8PrivateKey(derBytes) - if err != nil { - t.Errorf("failed to decode PKCS8 key: %s", err) + derBytes, _ := hex.DecodeString(pkcs8RSAPrivateKeyHex) + if _, err := ParsePKCS8PrivateKey(derBytes); err != nil { + t.Errorf("failed to decode PKCS8 with RSA private key: %s", err) + } + + derBytes, _ = hex.DecodeString(pkcs8ECPrivateKeyHex) + if _, err := ParsePKCS8PrivateKey(derBytes); err != nil { + t.Errorf("failed to decode PKCS8 with EC private key: %s", err) } } diff --git a/libgo/go/crypto/x509/sec1.go b/libgo/go/crypto/x509/sec1.go new file mode 100644 index 00000000000..8a2840fbef5 --- /dev/null +++ b/libgo/go/crypto/x509/sec1.go @@ -0,0 +1,69 @@ +// Copyright 2012 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 ( + "crypto/ecdsa" + "crypto/elliptic" + "encoding/asn1" + "errors" + "fmt" + "math/big" +) + +const ecPrivKeyVersion = 1 + +// ecPrivateKey reflects an ASN.1 Elliptic Curve Private Key Structure. +// References: +// RFC5915 +// SEC1 - http://www.secg.org/download/aid-780/sec1-v2.pdf +// Per RFC5915 the NamedCurveOID is marked as ASN.1 OPTIONAL, however in +// most cases it is not. +type ecPrivateKey struct { + Version int + PrivateKey []byte + NamedCurveOID asn1.ObjectIdentifier `asn1:"optional,explicit,tag:0"` + PublicKey asn1.BitString `asn1:"optional,explicit,tag:1"` +} + +// ParseECPrivateKey parses an ASN.1 Elliptic Curve Private Key Structure. +func ParseECPrivateKey(der []byte) (key *ecdsa.PrivateKey, err error) { + return parseECPrivateKey(nil, der) +} + +// parseECPrivateKey parses an ASN.1 Elliptic Curve Private Key Structure. +// The OID for the named curve may be provided from another source (such as +// the PKCS8 container) - if it is provided then use this instead of the OID +// that may exist in the EC private key structure. +func parseECPrivateKey(namedCurveOID *asn1.ObjectIdentifier, der []byte) (key *ecdsa.PrivateKey, err error) { + var privKey ecPrivateKey + if _, err := asn1.Unmarshal(der, &privKey); err != nil { + return nil, errors.New("crypto/x509: failed to parse EC private key: " + err.Error()) + } + if privKey.Version != ecPrivKeyVersion { + return nil, fmt.Errorf("crypto/x509: unknown EC private key version %d", privKey.Version) + } + + var curve elliptic.Curve + if namedCurveOID != nil { + curve = namedCurveFromOID(*namedCurveOID) + } else { + curve = namedCurveFromOID(privKey.NamedCurveOID) + } + if curve == nil { + return nil, errors.New("crypto/x509: unknown elliptic curve") + } + + k := new(big.Int).SetBytes(privKey.PrivateKey) + if k.Cmp(curve.Params().N) >= 0 { + return nil, errors.New("crypto/x509: invalid elliptic curve private key value") + } + priv := new(ecdsa.PrivateKey) + priv.Curve = curve + priv.D = k + priv.X, priv.Y = curve.ScalarBaseMult(privKey.PrivateKey) + + return priv, nil +} diff --git a/libgo/go/crypto/x509/sec1_test.go b/libgo/go/crypto/x509/sec1_test.go new file mode 100644 index 00000000000..7135699d283 --- /dev/null +++ b/libgo/go/crypto/x509/sec1_test.go @@ -0,0 +1,22 @@ +// Copyright 2012 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 ( + "encoding/hex" + "testing" +) + +// Generated using: +// openssl ecparam -genkey -name secp384r1 -outform PEM +var ecPrivateKeyHex = `3081a40201010430bdb9839c08ee793d1157886a7a758a3c8b2a17a4df48f17ace57c72c56b4723cf21dcda21d4e1ad57ff034f19fcfd98ea00706052b81040022a16403620004feea808b5ee2429cfcce13c32160e1c960990bd050bb0fdf7222f3decd0a55008e32a6aa3c9062051c4cba92a7a3b178b24567412d43cdd2f882fa5addddd726fe3e208d2c26d733a773a597abb749714df7256ead5105fa6e7b3650de236b50` + +func TestParseECPrivateKey(t *testing.T) { + derBytes, _ := hex.DecodeString(ecPrivateKeyHex) + _, err := ParseECPrivateKey(derBytes) + if err != nil { + t.Errorf("failed to decode EC private key: %s", err) + } +} diff --git a/libgo/go/crypto/x509/x509.go b/libgo/go/crypto/x509/x509.go index cfefbc5acec..7983217696e 100644 --- a/libgo/go/crypto/x509/x509.go +++ b/libgo/go/crypto/x509/x509.go @@ -156,8 +156,8 @@ const ( // // pkcs-1 OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 } -// -// +// +// // RFC 3279 2.2.1 RSA Signature Algorithms // // md2WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 2 } @@ -165,19 +165,19 @@ const ( // md5WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 } // // sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 } -// +// // dsaWithSha1 OBJECT IDENTIFIER ::= { -// iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 3 } +// iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 3 } // // RFC 3279 2.2.3 ECDSA Signature Algorithm -// +// // ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) ansi-x962(10045) // signatures(4) ecdsa-with-SHA1(1)} // // // RFC 4055 5 PKCS #1 Version 1.5 -// +// // sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 } // // sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 } @@ -1224,7 +1224,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub interf SerialNumber: template.SerialNumber, SignatureAlgorithm: signatureAlgorithm, Issuer: asn1.RawValue{FullBytes: asn1Issuer}, - Validity: validity{template.NotBefore, template.NotAfter}, + Validity: validity{template.NotBefore.UTC(), template.NotAfter.UTC()}, Subject: asn1.RawValue{FullBytes: asn1Subject}, PublicKey: publicKeyInfo{nil, publicKeyAlgorithm, encodedPublicKey}, Extensions: extensions, @@ -1314,8 +1314,8 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts [ Algorithm: oidSignatureSHA1WithRSA, }, Issuer: c.Subject.ToRDNSequence(), - ThisUpdate: now, - NextUpdate: expiry, + ThisUpdate: now.UTC(), + NextUpdate: expiry.UTC(), RevokedCertificates: revokedCerts, } |