1// Copyright 2015 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package pkcs12
6
7import (
8	"crypto/ecdsa"
9	"crypto/elliptic"
10	"crypto/rsa"
11	"crypto/x509"
12	"crypto/x509/pkix"
13	"encoding/asn1"
14	"errors"
15)
16
17type pkcs8 struct { // Duplicated from x509 package
18	Version    int
19	Algo       pkix.AlgorithmIdentifier
20	PrivateKey []byte
21}
22
23var ( // Duplicated from x509 package
24	oidPublicKeyRSA   = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
25	oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
26)
27
28var ( // Duplicated from x509 package
29	oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33}
30	oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7}
31	oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34}
32	oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35}
33)
34
35func oidFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) { // Duplicated from x509 package
36	switch curve {
37	case elliptic.P224():
38		return oidNamedCurveP224, true
39	case elliptic.P256():
40		return oidNamedCurveP256, true
41	case elliptic.P384():
42		return oidNamedCurveP384, true
43	case elliptic.P521():
44		return oidNamedCurveP521, true
45	}
46
47	return nil, false
48}
49
50func marshalPKCS8PrivateKey(key interface{}) (der []byte, err error) {
51	var privKey pkcs8
52	switch key := key.(type) {
53	case *rsa.PrivateKey:
54		privKey.Algo.Algorithm = oidPublicKeyRSA
55		// This is a NULL parameters value which is technically
56		// superfluous, but most other code includes it.
57		privKey.Algo.Parameters = asn1.RawValue{
58			Tag: 5,
59		}
60		privKey.PrivateKey = x509.MarshalPKCS1PrivateKey(key)
61	case *ecdsa.PrivateKey:
62		privKey.Algo.Algorithm = oidPublicKeyECDSA
63		namedCurveOID, ok := oidFromNamedCurve(key.Curve)
64		if !ok {
65			return nil, errors.New("pkcs12: unknown elliptic curve")
66		}
67		if privKey.Algo.Parameters.FullBytes, err = asn1.Marshal(namedCurveOID); err != nil {
68			return nil, errors.New("pkcs12: failed to embed OID of named curve in PKCS#8: " + err.Error())
69		}
70		if privKey.PrivateKey, err = x509.MarshalECPrivateKey(key); err != nil {
71			return nil, errors.New("pkcs12: failed to embed EC private key in PKCS#8: " + err.Error())
72		}
73	default:
74		return nil, errors.New("pkcs12: only RSA and ECDSA private keys supported")
75	}
76	return asn1.Marshal(privKey)
77}
78