aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaxim Fedorov <[email protected]>2018-05-10 12:48:15 -0700
committerMaxim Fedorov <[email protected]>2018-05-21 16:46:56 -0700
commit9539125a8ee97855e7cca4a8060cbf91957d0d98 (patch)
treeb22020ba3d1d2f5e182d324e8e1ad0b1398c9c44
parent304dd8f81e28ed04cde9f6f7ac1f79870da1c2cd (diff)
downloadotp-9539125a8ee97855e7cca4a8060cbf91957d0d98.tar.gz
otp-9539125a8ee97855e7cca4a8060cbf91957d0d98.tar.bz2
otp-9539125a8ee97855e7cca4a8060cbf91957d0d98.zip
PKCS8 handling improvements:
* added PKCS8 encoder for DSA, RSA and EC private keys * added tests (full loop, PKCS8 decode/encode operations) * rewritten private key decoder to be more Erlang-y
-rw-r--r--lib/public_key/src/pubkey_pem.erl2
-rw-r--r--lib/public_key/src/public_key.erl51
-rw-r--r--lib/public_key/test/public_key_SUITE.erl29
3 files changed, 54 insertions, 28 deletions
diff --git a/lib/public_key/src/pubkey_pem.erl b/lib/public_key/src/pubkey_pem.erl
index 06a4455b3f..bacc9ec600 100644
--- a/lib/public_key/src/pubkey_pem.erl
+++ b/lib/public_key/src/pubkey_pem.erl
@@ -209,6 +209,8 @@ pem_start('DSAPrivateKey') ->
<<"-----BEGIN DSA PRIVATE KEY-----">>;
pem_start('DHParameter') ->
<<"-----BEGIN DH PARAMETERS-----">>;
+pem_start('PrivateKeyInfo') ->
+ <<"-----BEGIN PRIVATE KEY-----">>;
pem_start('EncryptedPrivateKeyInfo') ->
<<"-----BEGIN ENCRYPTED PRIVATE KEY-----">>;
pem_start('CertificationRequest') ->
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index 6900ede946..42fbd59e3c 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -204,6 +204,24 @@ pem_entry_encode('SubjectPublicKeyInfo',
{'AlgorithmIdentifier', ?'id-ecPublicKey', Params},
Key},
pem_entry_encode('SubjectPublicKeyInfo', Spki);
+pem_entry_encode('PrivateKeyInfo', #'DSAPrivateKey'{p=P, q=Q, g=G, x=X}) ->
+ pem_entry_encode('PrivateKeyInfo',
+ {'PrivateKeyInfo', v1,
+ {'PrivateKeyInfo_privateKeyAlgorithm', ?'id-dsa',
+ {asn1_OPENTYPE, der_encode('Dss-Parms', #'Dss-Parms'{p=P, q=Q, g=G})}},
+ der_encode('Prime-p', X), asn1_NOVALUE});
+pem_entry_encode('PrivateKeyInfo', #'RSAPrivateKey'{} = PrivKey) ->
+ pem_entry_encode('PrivateKeyInfo',
+ {'PrivateKeyInfo', v1,
+ {'PrivateKeyInfo_privateKeyAlgorithm', ?'rsaEncryption',
+ {asn1_OPENTYPE, <<5, 0>>}},
+ der_encode('RSAPrivateKey', PrivKey), asn1_NOVALUE});
+pem_entry_encode('PrivateKeyInfo', #'ECPrivateKey'{parameters = Parameters} = PrivKey) ->
+ pem_entry_encode('PrivateKeyInfo',
+ {'PrivateKeyInfo', v1,
+ {'PrivateKeyInfo_privateKeyAlgorithm', ?'id-ecPublicKey',
+ {asn1_OPENTYPE, der_encode('EcpkParameters', Parameters)}},
+ der_encode('ECPrivateKey', PrivKey#'ECPrivateKey'{parameters = asn1_NOVALUE}), asn1_NOVALUE});
pem_entry_encode(Asn1Type, Entity) when is_atom(Asn1Type) ->
Der = der_encode(Asn1Type, Entity),
{Asn1Type, Der, not_encrypted}.
@@ -252,6 +270,21 @@ der_decode(Asn1Type, Der) when is_atom(Asn1Type), is_binary(Der) ->
erlang:error(Error)
end.
+der_priv_key_decode({'PrivateKeyInfo', v1,
+ {'PrivateKeyInfo_privateKeyAlgorithm', ?'id-ecPublicKey', {asn1_OPENTYPE, Parameters}}, PrivKey, _}) ->
+ EcPrivKey = der_decode('ECPrivateKey', PrivKey),
+ EcPrivKey#'ECPrivateKey'{parameters = der_decode('EcpkParameters', Parameters)};
+der_priv_key_decode({'PrivateKeyInfo', v1,
+ {'PrivateKeyInfo_privateKeyAlgorithm', ?'rsaEncryption', _}, PrivKey, _}) ->
+ der_decode('RSAPrivateKey', PrivKey);
+der_priv_key_decode({'PrivateKeyInfo', v1,
+ {'PrivateKeyInfo_privateKeyAlgorithm', ?'id-dsa', {asn1_OPENTYPE, Parameters}}, PrivKey, _}) ->
+ {params, #'Dss-Parms'{p=P, q=Q, g=G}} = der_decode('DSAParams', Parameters),
+ X = der_decode('Prime-p', PrivKey),
+ #'DSAPrivateKey'{p=P, q=Q, g=G, x=X};
+der_priv_key_decode(PKCS8Key) ->
+ PKCS8Key.
+
%%--------------------------------------------------------------------
-spec der_encode(asn1_type(), term()) -> Der::binary().
%%
@@ -276,24 +309,6 @@ der_encode(Asn1Type, Entity) when is_atom(Asn1Type) ->
erlang:error(Error)
end.
-der_priv_key_decode({'PrivateKeyInfo', v1, PKAlgo, PrivKey, _} = PKCS8Key) ->
- % do actual decoding
- {'PrivateKeyInfo_privateKeyAlgorithm', Algorithm, {asn1_OPENTYPE, Parameters}} = PKAlgo,
- case Algorithm of
- ?'id-ecPublicKey' ->
- EcpkParameters = public_key:der_decode('EcpkParameters', Parameters),
- EcPrivKey = public_key:der_decode('ECPrivateKey', PrivKey),
- EcPrivKey#'ECPrivateKey'{parameters = EcpkParameters};
- ?'rsaEncryption' ->
- public_key:der_decode('RSAPrivateKey', PrivKey);
- ?'id-dsa' ->
- {params, #'Dss-Parms'{p=P, q=Q, g=G}} = public_key:der_decode('DSAParams', Parameters),
- X = public_key:der_decode('Prime-p', PrivKey),
- #'DSAPrivateKey'{p=P, q=Q, g=G, x=X};
- _ ->
- PKCS8Key
- end.
-
%%--------------------------------------------------------------------
-spec pkix_decode_cert(Cert::binary(), plain | otp) ->
#'Certificate'{} | #'OTPCertificate'{}.
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index f5a6f79136..572748edc9 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -183,14 +183,17 @@ dsa_pem(Config) when is_list(Config) ->
DSAPubPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([PubEntry0])).
dsa_priv_pkcs8() ->
- [{doc, "DSA PKCS8 private key decode"}].
+ [{doc, "DSA PKCS8 private key decode/encode"}].
dsa_priv_pkcs8(Config) when is_list(Config) ->
Datadir = proplists:get_value(data_dir, Config),
- [{'PrivateKeyInfo', DerDSAKey, not_encrypted} = Entry0 ] =
- erl_make_certs:pem_to_der(filename:join(Datadir, "dsa_key_pkcs8.pem")),
+ {ok, DsaPem} = file:read_file(filename:join(Datadir, "dsa_key_pkcs8.pem")),
+ [{'PrivateKeyInfo', DerDSAKey, not_encrypted} = Entry0 ] = public_key:pem_decode(DsaPem),
DSAKey = public_key:der_decode('PrivateKeyInfo', DerDSAKey),
DSAKey = public_key:pem_entry_decode(Entry0),
- true = check_entry_type(DSAKey, 'DSAPrivateKey').
+ true = check_entry_type(DSAKey, 'DSAPrivateKey'),
+ PrivEntry0 = public_key:pem_entry_encode('PrivateKeyInfo', DSAKey),
+ DSAPemNoEndNewLines = strip_superfluous_newlines(DsaPem),
+ DSAPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([PrivEntry0])).
%%--------------------------------------------------------------------
@@ -228,14 +231,17 @@ rsa_pem(Config) when is_list(Config) ->
RSARawPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([PubEntry1])).
rsa_priv_pkcs8() ->
- [{doc, "RSA PKCS8 private key decode"}].
+ [{doc, "RSA PKCS8 private key decode/encode"}].
rsa_priv_pkcs8(Config) when is_list(Config) ->
Datadir = proplists:get_value(data_dir, Config),
- [{'PrivateKeyInfo', DerRSAKey, not_encrypted} = Entry0 ] =
- erl_make_certs:pem_to_der(filename:join(Datadir, "rsa_key_pkcs8.pem")),
+ {ok, RsaPem} = file:read_file(filename:join(Datadir, "rsa_key_pkcs8.pem")),
+ [{'PrivateKeyInfo', DerRSAKey, not_encrypted} = Entry0 ] = public_key:pem_decode(RsaPem),
RSAKey = public_key:der_decode('PrivateKeyInfo', DerRSAKey),
RSAKey = public_key:pem_entry_decode(Entry0),
- true = check_entry_type(RSAKey, 'RSAPrivateKey').
+ true = check_entry_type(RSAKey, 'RSAPrivateKey'),
+ PrivEntry0 = public_key:pem_entry_encode('PrivateKeyInfo', RSAKey),
+ RSAPemNoEndNewLines = strip_superfluous_newlines(RsaPem),
+ RSAPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([PrivEntry0])).
%%--------------------------------------------------------------------
@@ -284,14 +290,17 @@ ec_pem2(Config) when is_list(Config) ->
ECPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([Entry1, Entry2])).
ec_priv_pkcs8() ->
- [{doc, "EC PKCS8 private key decode"}].
+ [{doc, "EC PKCS8 private key decode/encode"}].
ec_priv_pkcs8(Config) when is_list(Config) ->
Datadir = proplists:get_value(data_dir, Config),
{ok, ECPrivPem} = file:read_file(filename:join(Datadir, "ec_key_pkcs8.pem")),
[{'PrivateKeyInfo', _, not_encrypted} = PKCS8Key] = public_key:pem_decode(ECPrivPem),
ECPrivKey = public_key:pem_entry_decode(PKCS8Key),
true = check_entry_type(ECPrivKey, 'ECPrivateKey'),
- true = check_entry_type(ECPrivKey#'ECPrivateKey'.parameters, 'EcpkParameters').
+ true = check_entry_type(ECPrivKey#'ECPrivateKey'.parameters, 'EcpkParameters'),
+ PrivEntry0 = public_key:pem_entry_encode('PrivateKeyInfo', ECPrivKey),
+ ECPemNoEndNewLines = strip_superfluous_newlines(ECPrivPem),
+ ECPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([PrivEntry0])).
init_ec_pem_encode_generated(Config) ->
case catch true = lists:member('secp384r1', crypto:ec_curves()) of