aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngela Andin <[email protected]>2018-05-23 10:25:52 +0200
committerGitHub <[email protected]>2018-05-23 10:25:52 +0200
commit1aee7ab4f8eed47c5132a636beb829b9ba91755e (patch)
treedcad8ea61d21c3d3436a18edb51ea7ddefb05096
parent39328ee50d04bd7abfe835f295d92edd17701d64 (diff)
parent8125494dc169d86e6266842e2e1bfa712ee9ffa8 (diff)
downloadotp-1aee7ab4f8eed47c5132a636beb829b9ba91755e.tar.gz
otp-1aee7ab4f8eed47c5132a636beb829b9ba91755e.tar.bz2
otp-1aee7ab4f8eed47c5132a636beb829b9ba91755e.zip
Merge pull request #1788 from max-au/pkcs8_private_key_support
Compleate PKCS-8 encoding support and enhance the decoding of 'PrivateKeyInfo' to conform to the rest of Erlang public_key API. OTP-15093
-rw-r--r--lib/public_key/src/pubkey_pem.erl2
-rw-r--r--lib/public_key/src/public_key.erl37
-rw-r--r--lib/public_key/test/pbe_SUITE.erl10
-rw-r--r--lib/public_key/test/public_key_SUITE.erl39
-rw-r--r--lib/public_key/test/public_key_SUITE_data/dsa_key_pkcs8.pem9
-rw-r--r--lib/public_key/test/public_key_SUITE_data/ec_key_pkcs8.pem5
-rw-r--r--lib/public_key/test/public_key_SUITE_data/rsa_key_pkcs8.pem10
7 files changed, 102 insertions, 10 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 931901640a..1c4acc9e1a 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -237,7 +237,7 @@ der_decode(Asn1Type, Der) when (Asn1Type == 'PrivateKeyInfo') or
andalso is_binary(Der) ->
try
{ok, Decoded} = 'PKCS-FRAME':decode(Asn1Type, Der),
- Decoded
+ der_priv_key_decode(Decoded)
catch
error:{badmatch, {error, _}} = Error ->
erlang:error(Error)
@@ -252,12 +252,45 @@ 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().
%%
%% Description: Encodes a public key entity with asn1 DER encoding.
%%--------------------------------------------------------------------
-der_encode(Asn1Type, Entity) when (Asn1Type == 'PrivateKeyInfo') or
+
+der_encode('PrivateKeyInfo', #'DSAPrivateKey'{p=P, q=Q, g=G, x=X}) ->
+ der_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});
+der_encode('PrivateKeyInfo', #'RSAPrivateKey'{} = PrivKey) ->
+ der_encode('PrivateKeyInfo',
+ {'PrivateKeyInfo', v1,
+ {'PrivateKeyInfo_privateKeyAlgorithm', ?'rsaEncryption', {asn1_OPENTYPE, ?DER_NULL}},
+ der_encode('RSAPrivateKey', PrivKey), asn1_NOVALUE});
+der_encode('PrivateKeyInfo', #'ECPrivateKey'{parameters = Parameters} = PrivKey) ->
+ der_encode('PrivateKeyInfo',
+ {'PrivateKeyInfo', v1,
+ {'PrivateKeyInfo_privateKeyAlgorithm', ?'id-ecPublicKey',
+ {asn1_OPENTYPE, der_encode('EcpkParameters', Parameters)}},
+ der_encode('ECPrivateKey', PrivKey#'ECPrivateKey'{parameters = asn1_NOVALUE}), asn1_NOVALUE});
+der_encode(Asn1Type, Entity) when (Asn1Type == 'PrivateKeyInfo') or
(Asn1Type == 'EncryptedPrivateKeyInfo') ->
try
{ok, Encoded} = 'PKCS-FRAME':encode(Asn1Type, Entity),
diff --git a/lib/public_key/test/pbe_SUITE.erl b/lib/public_key/test/pbe_SUITE.erl
index 44caf479e5..8a5db4efec 100644
--- a/lib/public_key/test/pbe_SUITE.erl
+++ b/lib/public_key/test/pbe_SUITE.erl
@@ -226,11 +226,6 @@ pbes2(Config) when is_list(Config) ->
ok
end.
-check_key_info(#'PrivateKeyInfo'{privateKeyAlgorithm =
- #'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?rsaEncryption},
- privateKey = Key}) ->
- #'RSAPrivateKey'{} = public_key:der_decode('RSAPrivateKey', iolist_to_binary(Key)).
-
decode_encode_key_file(File, Password, Cipher, Config) ->
Datadir = proplists:get_value(data_dir, Config),
{ok, PemKey} = file:read_file(filename:join(Datadir, File)),
@@ -238,11 +233,10 @@ decode_encode_key_file(File, Password, Cipher, Config) ->
PemEntry = public_key:pem_decode(PemKey),
ct:print("Pem entry: ~p" , [PemEntry]),
[{Asn1Type, _, {Cipher,_} = CipherInfo} = PubEntry] = PemEntry,
- KeyInfo = public_key:pem_entry_decode(PubEntry, Password),
+ #'RSAPrivateKey'{} = KeyInfo = public_key:pem_entry_decode(PubEntry, Password),
PemKey1 = public_key:pem_encode([public_key:pem_entry_encode(Asn1Type, KeyInfo, {CipherInfo, Password})]),
Pem = strip_ending_newlines(PemKey),
- Pem = strip_ending_newlines(PemKey1),
- check_key_info(KeyInfo).
+ Pem = strip_ending_newlines(PemKey1).
strip_ending_newlines(Bin) ->
string:strip(binary_to_list(Bin), right, 10).
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index 449d1fc040..572748edc9 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -64,6 +64,7 @@ all() ->
groups() ->
[{pem_decode_encode, [], [dsa_pem, rsa_pem, ec_pem, encrypted_pem,
dh_pem, cert_pem, pkcs7_pem, pkcs10_pem, ec_pem2,
+ rsa_priv_pkcs8, dsa_priv_pkcs8, ec_priv_pkcs8,
ec_pem_encode_generated,
gen_ec_param_prime_field, gen_ec_param_char_2_field
]},
@@ -181,6 +182,19 @@ dsa_pem(Config) when is_list(Config) ->
DSAPubPemNoEndNewLines = strip_superfluous_newlines(DSAPubPem),
DSAPubPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([PubEntry0])).
+dsa_priv_pkcs8() ->
+ [{doc, "DSA PKCS8 private key decode/encode"}].
+dsa_priv_pkcs8(Config) when is_list(Config) ->
+ Datadir = proplists:get_value(data_dir, Config),
+ {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'),
+ PrivEntry0 = public_key:pem_entry_encode('PrivateKeyInfo', DSAKey),
+ DSAPemNoEndNewLines = strip_superfluous_newlines(DsaPem),
+ DSAPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([PrivEntry0])).
+
%%--------------------------------------------------------------------
rsa_pem() ->
@@ -216,6 +230,19 @@ rsa_pem(Config) when is_list(Config) ->
RSARawPemNoEndNewLines = strip_superfluous_newlines(RSARawPem),
RSARawPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([PubEntry1])).
+rsa_priv_pkcs8() ->
+ [{doc, "RSA PKCS8 private key decode/encode"}].
+rsa_priv_pkcs8(Config) when is_list(Config) ->
+ Datadir = proplists:get_value(data_dir, Config),
+ {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'),
+ PrivEntry0 = public_key:pem_entry_encode('PrivateKeyInfo', RSAKey),
+ RSAPemNoEndNewLines = strip_superfluous_newlines(RsaPem),
+ RSAPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([PrivEntry0])).
+
%%--------------------------------------------------------------------
ec_pem() ->
@@ -262,6 +289,18 @@ ec_pem2(Config) when is_list(Config) ->
ECPemNoEndNewLines = strip_superfluous_newlines(ECPrivPem),
ECPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([Entry1, Entry2])).
+ec_priv_pkcs8() ->
+ [{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'),
+ 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
diff --git a/lib/public_key/test/public_key_SUITE_data/dsa_key_pkcs8.pem b/lib/public_key/test/public_key_SUITE_data/dsa_key_pkcs8.pem
new file mode 100644
index 0000000000..86e38e2c76
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/dsa_key_pkcs8.pem
@@ -0,0 +1,9 @@
+-----BEGIN PRIVATE KEY-----
+MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBALez5tklY5CdFeTMos899pA6i4u4
+uCtszgBzrdBk6cl5FVqzdzWMGTQiynnTpGsrOESinzP06Ip+pG15We2OORwgvCxD
+/W95aCiN0/+MdiXqlsmboBARMzsa+SmBENN3gF/+tuuEAFzOXU1q2cmEywRLyfbM
+2KIBVE/TChWYw2eRAhUA1R64VvcQ90XA8SOKVDmMA0dBzukCgYEAlLMYP0pbgBlg
+HQVO3/avAHlWNrIq52Lxk7SdPJWgMvPjTK9Z6sv88kxsCcydtjvO439j1yqcwk50
+GQc+86ktBWWz93/HkIdnFyqafef4mmWvm2Uq6ClQKS+A0Asfaj8Mys+HUMiI+qsf
+djRbyIpwb7MX1nsVdsKzALnZNMW27A0EFgIUWYCfDrv5tqwPWKJu00ez0R192SY=
+-----END PRIVATE KEY-----
diff --git a/lib/public_key/test/public_key_SUITE_data/ec_key_pkcs8.pem b/lib/public_key/test/public_key_SUITE_data/ec_key_pkcs8.pem
new file mode 100644
index 0000000000..8280a3671a
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/ec_key_pkcs8.pem
@@ -0,0 +1,5 @@
+-----BEGIN PRIVATE KEY-----
+MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgB349XXSmba5BbJT5UuCK
+OoyoPHsygy6n+WzP1J+8eYShRANCAATTJdDtiqV9Hs7q+Y/yak1z3uJpukFQGYmr
+lJ2iztxfv7bz10eJ5yM/GNqG8kK0w7SIzjedsIkfjRK7bX6mP7h4
+-----END PRIVATE KEY-----
diff --git a/lib/public_key/test/public_key_SUITE_data/rsa_key_pkcs8.pem b/lib/public_key/test/public_key_SUITE_data/rsa_key_pkcs8.pem
new file mode 100644
index 0000000000..9ef5b3353f
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/rsa_key_pkcs8.pem
@@ -0,0 +1,10 @@
+-----BEGIN PRIVATE KEY-----
+MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEA1GLJmDS5yLvg1zqa
+epnwCgOXzxpPvHokDQx+AcgfO14SPtCD6UTlDEwYBp+6tUTm+qgeQN/CTi7POwIA
+m7P3UwIDAQABAkALFiEJ1e7AwLXq5j88GR8Dls5s3CW/Y+zP1ZAaTbT7p0QUMxG+
+0ko7h8NoxcQJHZU27sZXCjog/IBqn577Xv4RAiEA8/aQ09kz0jxi4aNvlix4B+bW
+gX0sYtcCDkBzx8Y6iMkCIQDe3WCxV9PuiDjpuC8cAy3UMC5PBygZG4iK3arpgzxp
+OwIhAKxKJg+mpgVEJiTpsiVhNEeIS1bZWp5W75m3BM1B/haZAiBQOhEcxikcrR0P
+xaXvx5Uv1UhWWpUstKSqmLF17jBJEQIhAMx4HMLqwaGeYwOcxfzxz6Al8fnPmfAR
+hqFR28fVJrWX
+-----END PRIVATE KEY-----