]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/x509, crypto/tls: support PKCS#8 private keys.
authorAdam Langley <agl@golang.org>
Mon, 21 Nov 2011 19:18:42 +0000 (14:18 -0500)
committerAdam Langley <agl@golang.org>
Mon, 21 Nov 2011 19:18:42 +0000 (14:18 -0500)
OpenSSL 1.0.0 has switched to generating PKCS#8 format private keys by
default. This change allows http.ListenAndServeTLS to work with either
types of keys.

See http://groups.google.com/group/golang-nuts/browse_thread/thread/84715b5f0c9e3c30/63a8a27b53e102a6

R=bradfitz
CC=golang-dev
https://golang.org/cl/5416059

src/pkg/crypto/tls/tls.go
src/pkg/crypto/x509/Makefile
src/pkg/crypto/x509/pkcs8.go [new file with mode: 0644]
src/pkg/crypto/x509/pkcs8_test.go [new file with mode: 0644]

index 3ca62407ff032dcb6f4449fa77555c78f615eb7c..79ab50231293045e6b0eed4f0efd88818163fb24 100644 (file)
@@ -157,10 +157,21 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err error)
                return
        }
 
-       key, err := x509.ParsePKCS1PrivateKey(keyDERBlock.Bytes)
-       if err != nil {
-               err = errors.New("crypto/tls: failed to parse key: " + err.Error())
-               return
+       // OpenSSL 0.9.8 generates PKCS#1 private keys by default, while
+       // OpenSSL 1.0.0 generates PKCS#8 keys. We try both.
+       var key *rsa.PrivateKey
+       if key, err = x509.ParsePKCS1PrivateKey(keyDERBlock.Bytes); err != nil {
+               var privKey interface{}
+               if privKey, err = x509.ParsePKCS8PrivateKey(keyDERBlock.Bytes); err != nil {
+                       err = errors.New("crypto/tls: failed to parse key: " + err.Error())
+                       return
+               }
+
+               var ok bool
+               if key, ok = privKey.(*rsa.PrivateKey); !ok {
+                       err = errors.New("crypto/tls: found non-RSA private key in PKCS#8 wrapping")
+                       return
+               }
        }
 
        cert.PrivateKey = key
index abc43abb6c1d1a4ec7c318a5de46c0cd95cc47f1..91d1052c0d051dd49f1f9fc948bd4b53471ba530 100644 (file)
@@ -8,6 +8,7 @@ TARG=crypto/x509
 GOFILES=\
        cert_pool.go\
        pkcs1.go\
+       pkcs8.go\
        verify.go\
        x509.go\
 
diff --git a/src/pkg/crypto/x509/pkcs8.go b/src/pkg/crypto/x509/pkcs8.go
new file mode 100644 (file)
index 0000000..4d8e051
--- /dev/null
@@ -0,0 +1,42 @@
+// 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 (
+       "crypto/x509/pkix"
+       "encoding/asn1"
+       "errors"
+       "fmt"
+)
+
+// pkcs8 reflects an ASN.1, PKCS#8 PrivateKey. See 
+// ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-8/pkcs-8v1_2.asn.
+type pkcs8 struct {
+       Version    int
+       Algo       pkix.AlgorithmIdentifier
+       PrivateKey []byte
+       // optional attributes omitted.
+}
+
+// ParsePKCS8PrivateKey parses an unencrypted, PKCS#8 private key. See
+// http://www.rsa.com/rsalabs/node.asp?id=2130
+func ParsePKCS8PrivateKey(der []byte) (key interface{}, err error) {
+       var privKey pkcs8
+       if _, err := asn1.Unmarshal(der, &privKey); err != nil {
+               return nil, err
+       }
+       switch {
+       case privKey.Algo.Algorithm.Equal(oidRSA):
+               key, err = ParsePKCS1PrivateKey(privKey.PrivateKey)
+               if err != nil {
+                       return nil, errors.New("crypto/x509: failed to parse RSA 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)
+       }
+
+       panic("unreachable")
+}
diff --git a/src/pkg/crypto/x509/pkcs8_test.go b/src/pkg/crypto/x509/pkcs8_test.go
new file mode 100644 (file)
index 0000000..372005f
--- /dev/null
@@ -0,0 +1,20 @@
+// 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 (
+       "encoding/hex"
+       "testing"
+)
+
+var pkcs8PrivateKeyHex = `30820278020100300d06092a864886f70d0101010500048202623082025e02010002818100cfb1b5bf9685ffa97b4f99df4ff122b70e59ac9b992f3bc2b3dde17d53c1a34928719b02e8fd17839499bfbd515bd6ef99c7a1c47a239718fe36bfd824c0d96060084b5f67f0273443007a24dfaf5634f7772c9346e10eb294c2306671a5a5e719ae24b4de467291bc571014b0e02dec04534d66a9bb171d644b66b091780e8d020301000102818100b595778383c4afdbab95d2bfed12b3f93bb0a73a7ad952f44d7185fd9ec6c34de8f03a48770f2009c8580bcd275e9632714e9a5e3f32f29dc55474b2329ff0ebc08b3ffcb35bc96e6516b483df80a4a59cceb71918cbabf91564e64a39d7e35dce21cb3031824fdbc845dba6458852ec16af5dddf51a8397a8797ae0337b1439024100ea0eb1b914158c70db39031dd8904d6f18f408c85fbbc592d7d20dee7986969efbda081fdf8bc40e1b1336d6b638110c836bfdc3f314560d2e49cd4fbde1e20b024100e32a4e793b574c9c4a94c8803db5152141e72d03de64e54ef2c8ed104988ca780cd11397bc359630d01b97ebd87067c5451ba777cf045ca23f5912f1031308c702406dfcdbbd5a57c9f85abc4edf9e9e29153507b07ce0a7ef6f52e60dcfebe1b8341babd8b789a837485da6c8d55b29bbb142ace3c24a1f5b54b454d01b51e2ad03024100bd6a2b60dee01e1b3bfcef6a2f09ed027c273cdbbaf6ba55a80f6dcc64e4509ee560f84b4f3e076bd03b11e42fe71a3fdd2dffe7e0902c8584f8cad877cdc945024100aa512fa4ada69881f1d8bb8ad6614f192b83200aef5edf4811313d5ef30a86cbd0a90f7b025c71ea06ec6b34db6306c86b1040670fd8654ad7291d066d06d031`
+
+func TestPKCS8(t *testing.T) {
+       derBytes, _ := hex.DecodeString(pkcs8PrivateKeyHex)
+       _, err := ParsePKCS8PrivateKey(derBytes)
+       if err != nil {
+               t.Errorf("failed to decode PKCS8 key: %s", err)
+       }
+}