2
%% <year>2008-2008</year>
3
%% <holder>Ericsson AB, All Rights Reserved</holder>
6
%% The contents of this file are subject to the Erlang Public License,
7
%% Version 1.1, (the "License"); you may not use this file except in
8
%% compliance with the License. You should have received a copy of the
9
%% Erlang Public License along with this software. If not, it can be
10
%% retrieved online at http://www.erlang.org/.
12
%% Software distributed under the License is distributed on an "AS IS"
13
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
14
%% the License for the specific language governing rights and limitations
17
%% The Initial Developer of the Original Code is Ericsson AB.
23
-include("public_key.hrl").
25
-export([decode_private_key/1, decode_private_key/2,
26
decrypt_private/2, decrypt_private/3, encrypt_public/2,
27
encrypt_public/3, decrypt_public/2, decrypt_public/3,
28
encrypt_private/2, encrypt_private/3,
30
verify_signature/3, verify_signature/4, verify_signature/5,
31
pem_to_der/1, pem_to_der/2,
32
pkix_decode_cert/2, pkix_encode_cert/1,
33
pkix_is_self_signed/1, pkix_is_fixed_dh_cert/1,
35
pkix_is_issuer/2, pkix_normalize_general_name/1,
36
pkix_path_validation/3
39
%%====================================================================
41
%%====================================================================
43
%%--------------------------------------------------------------------
44
%% Function: decode_private_key(KeyInfo [,Password]) ->
45
%% {ok, PrivateKey} | {error, Reason}
47
%% KeyInfo = {Type, der_bin(), ChipherInfo} - as returned from
48
%% pem_to_der/[1,2] for private keys
49
%% Type = rsa_private_key | dsa_private_key
50
%% ChipherInfo = opaque() | no_encryption
52
%% Description: Decodes an asn1 der encoded private key.
53
%%--------------------------------------------------------------------
54
decode_private_key(KeyInfo) ->
55
decode_private_key(KeyInfo, no_passwd).
57
decode_private_key(KeyInfo = {rsa_private_key, _, _}, Password) ->
58
DerEncoded = pubkey_pem:decode_key(KeyInfo, Password),
59
'OTP-PUB-KEY':decode('RSAPrivateKey', DerEncoded);
60
decode_private_key(KeyInfo = {dsa_private_key, _, _}, Password) ->
61
DerEncoded = pubkey_pem:decode_key(KeyInfo, Password),
62
'OTP-PUB-KEY':decode('DSAPrivateKey', DerEncoded).
64
%%--------------------------------------------------------------------
65
%% Function: decrypt_private(CipherText, Key) ->
66
%% decrypt_private(CipherText, Key, Options) -> PlainTex
67
%% decrypt_public(CipherText, Key) ->
68
%% decrypt_public(CipherText, Key, Options) -> PlainTex
70
%% CipherText = binary()
72
%% PlainText = binary()
74
%% Description: Decrypts <CipherText>.
75
%%--------------------------------------------------------------------
76
decrypt_private(CipherText, Key) ->
77
decrypt_private(CipherText, Key, []).
78
decrypt_private(CipherText, Key, Options) ->
79
Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
80
pubkey_crypto:decrypt_private(CipherText, Key, Padding).
82
decrypt_public(CipherText, Key) ->
83
decrypt_public(CipherText, Key, []).
84
decrypt_public(CipherText, Key, Options) ->
85
Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
86
pubkey_crypto:decrypt_public(CipherText, Key, Padding).
88
%%--------------------------------------------------------------------
89
%% Function: encrypt_public(PlainText, Key, Options) -> CipherText
90
%% encrypt_private(PlainText, Key, Options) -> CipherText
92
%% PlainText = iolist()
93
%% Key = rsa_private_key()
94
%% CipherText = binary()
96
%% Description: Encrypts <Plain>
97
%%--------------------------------------------------------------------
98
encrypt_public(PlainText, Key) ->
99
encrypt_public(PlainText, Key, []).
100
encrypt_public(PlainText, Key, Options) ->
101
Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_oaep_padding),
102
pubkey_crypto:encrypt_public(PlainText, Key, Padding).
104
encrypt_private(PlainText, Key) ->
105
encrypt_private(PlainText, Key, []).
106
encrypt_private(PlainText, Key, Options) ->
107
Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_oaep_padding),
108
pubkey_crypto:encrypt_private(PlainText, Key, Padding).
110
%%--------------------------------------------------------------------
111
%% Function: pem_to_der(File) ->
112
%% pem_to_der(File, Password) -> {ok, [Entry]} | {error, Reason}
115
%% Password = string()
116
%% Entry = {entry_type(), der_bin(), ChipherInfo}
117
%% ChipherInfo = opague() | no_encryption
118
%% der_bin() = binary()
119
%% entry_type() = cert | cert_req | rsa_private_key | dsa_private_key
122
%% Description: Read and decode PEM file and returns entries as asn1
123
%% der encoded entities. Currently supported entry types are
124
%% certificates, certificate requests, rsa private keys and dsa
125
%% private keys. In the case of a key entry ChipherInfo will be
126
%% used by decode_private_key/2 if the key is protected by a password.
127
%%--------------------------------------------------------------------
129
pubkey_pem:read_file(File).
131
pem_to_der(File, Password) ->
132
pubkey_pem:read_file(File, Password).
134
%%--------------------------------------------------------------------
135
%% Function: pkix_decode_cert(BerCert, Type) -> {ok, Cert} | {error, Reason}
137
%% BerCert = binary()
138
%% Type = plain | otp
139
%% Cert = certificate()
141
%% Description: Decodes an asn1 ber encoded pkix certificate.
142
%% otp - Uses OTP-PKIX.asn1 to decode known extensions and
143
%% enhance the signature field in #'Certificate'{} and '#TBSCertificate'{}.
144
%%--------------------------------------------------------------------
145
pkix_decode_cert(BinCert, Type) ->
146
pubkey_cert_records:decode_cert(BinCert, Type).
148
%%--------------------------------------------------------------------
149
%% Function: pkix_encode_cert(Cert) -> {ok, binary()} | {error, Reason}
151
%% Cert = #'Certificate'{}
153
%% Description: Encodes a certificate record using asn1.
154
%%--------------------------------------------------------------------
155
pkix_encode_cert(Cert) ->
156
pubkey_cert_records:encode_cert(Cert).
158
%%--------------------------------------------------------------------
159
%% Function: pkix_path_validation(TrustedCert, CertChain, Options) ->
160
%% {ok, {{algorithm(), public_key(), public_key_params()} policy_tree()}} |
163
%% Description: Performs a bacis path validation according to RFC 3280.
164
%%--------------------------------------------------------------------
165
pkix_path_validation(TrustedCert, CertChain, Options)
166
when is_binary(TrustedCert) ->
167
{ok, OtpCert} = pkix_decode_cert(TrustedCert, otp),
168
pkix_path_validation(OtpCert, CertChain, Options);
170
pkix_path_validation(#'OTPCertificate'{} = TrustedCert, CertChain, Options)
171
when is_list(CertChain), is_list(Options) ->
172
MaxPathDefault = length(CertChain),
173
ValidationState = pubkey_cert:init_validation_state(TrustedCert,
176
Fun = proplists:get_value(validate_extensions_fun, Options,
177
fun(Extensions, State, _, AccError) ->
178
{Extensions, State, AccError}
180
Verify = proplists:get_value(verify, Options, true),
181
path_validation(CertChain, ValidationState, Fun, Verify).
182
%%--------------------------------------------------------------------
183
%% Function: pkix_is_fixed_dh_cert(Cert) -> true | false
185
%% Description: Checks if a Certificate is a fixed Diffie-Hellman Cert
186
%%--------------------------------------------------------------------
187
pkix_is_fixed_dh_cert(#'OTPCertificate'{} = OTPCert) ->
188
pubkey_cert:is_fixed_dh_cert(OTPCert);
189
pkix_is_fixed_dh_cert(Cert) when is_binary(Cert) ->
190
{ok, OtpCert} = pkix_decode_cert(Cert, otp),
191
pkix_is_fixed_dh_cert(OtpCert).
193
%%--------------------------------------------------------------------
194
%% Function: pkix_is_self_signed(Cert) -> true | false
196
%% Description: Checks if a Certificate is self signed.
197
%%--------------------------------------------------------------------
198
pkix_is_self_signed(#'OTPCertificate'{} = OTPCert) ->
199
pubkey_cert:is_self_signed(OTPCert);
200
pkix_is_self_signed(Cert) when is_binary(Cert) ->
201
{ok, OtpCert} = pkix_decode_cert(Cert, otp),
202
pkix_is_self_signed(OtpCert).
204
%%--------------------------------------------------------------------
205
%% Function: pkix_issuer_id(Cert) -> {ok, {SerialNr, Issuer}} | {error, Reason}
207
%% Cert = asn1_der_encoded() | 'OTPCertificate'{}
209
%% Description: Returns the issuer id.
210
%%--------------------------------------------------------------------
211
pkix_issuer_id(#'OTPCertificate'{} = OtpCert, self) ->
212
pubkey_cert:issuer_id(OtpCert, self);
214
pkix_issuer_id(#'OTPCertificate'{} = OtpCert, other) ->
215
pubkey_cert:issuer_id(OtpCert, other);
217
pkix_issuer_id(Cert, Signed) when is_binary(Cert) ->
218
{ok, OtpCert} = pkix_decode_cert(Cert, otp),
219
pkix_issuer_id(OtpCert, Signed).
221
%%--------------------------------------------------------------------
222
%% Function: pkix_is_issuer(Cert, IssuerCert) -> true | false
224
%% Cert = asn1_der_encoded() | 'OTPCertificate'{}
225
%% IssuerCert = asn1_der_encoded() | 'OTPCertificate'{}
227
%% Description: Checks if <IssuerCert> issued <Cert>.
228
%%--------------------------------------------------------------------
229
pkix_is_issuer(Cert, IssuerCert) when is_binary(Cert) ->
230
{ok, OtpCert} = pkix_decode_cert(Cert, otp),
231
pkix_is_issuer(OtpCert, IssuerCert);
233
pkix_is_issuer(Cert, IssuerCert) when is_binary(IssuerCert) ->
234
{ok, OtpIssuerCert} = pkix_decode_cert(IssuerCert, otp),
235
pkix_is_issuer(Cert, OtpIssuerCert);
237
pkix_is_issuer(#'OTPCertificate'{tbsCertificate = TBSCert},
238
#'OTPCertificate'{tbsCertificate = Candidate}) ->
239
pubkey_cert:is_issuer(TBSCert#'OTPTBSCertificate'.issuer,
240
Candidate#'OTPTBSCertificate'.subject).
242
%%--------------------------------------------------------------------
243
%% Function: pkix_normalize_general_name(Issuer) ->
245
%% Issuer = general_name() - see PKIX
247
%% Description: Normalizes a general name so that it can be easily
248
%% compared to another genral name.
249
%%--------------------------------------------------------------------
250
pkix_normalize_general_name(Issuer) ->
251
pubkey_cert:normalize_general_name(Issuer).
253
%%--------------------------------------------------------------------
254
%% Function:sign(Msg, Key) -> {ok, Signature}
255
%% sign(Msg, Key, KeyParams) -> {ok, Signature}
257
%% Msg = binary() | #'TBSCertificate'{}
258
%% Key = private_key()
259
%% KeyParams = key_params()
260
%% Signature = binary()
262
%% Description: Signs plaintext Msg or #TBSCertificate{}, in the later
263
%% case a der encoded "#Certificate{}" will be returned.
264
%%--------------------------------------------------------------------
265
sign(Msg, #'RSAPrivateKey'{} = Key) when is_binary(Msg) ->
266
pubkey_crypto:sign(Msg, Key);
268
sign(Msg, #'DSAPrivateKey'{} = Key) when is_binary(Msg) ->
269
pubkey_crypto:sign(Msg, Key);
271
sign(#'OTPTBSCertificate'{signature = SigAlg} = TBSCert, Key) ->
272
Msg = pubkey_cert_records:encode_tbs_cert(TBSCert),
273
DigestType = pubkey_cert:digest_type(SigAlg),
274
Signature = pubkey_crypto:sign(DigestType, Msg, Key),
275
Cert = #'OTPCertificate'{tbsCertificate= TBSCert,
276
signatureAlgorithm = SigAlg,
277
signature = {0, Signature}
279
pkix_encode_cert(Cert).
281
sign(DigestType, Msg, Key) ->
282
pubkey_crypto:sign(DigestType, Msg, Key).
284
%%--------------------------------------------------------------------
285
%% Function: verify_signature(PlainText, DigestType, Signature, Key) ->
286
%% verify_signature(PlainText, DigestType,
287
%% Signature, Key, KeyParams) ->
288
%% verify_signature(DerCert, Key, KeyParams) ->
290
%% PlainText = binary()
291
%% DigestType = md5 | sha
292
%% DerCert = asn1_der_encoded()
293
%% Signature = binary()
294
%% Key = public_key()
295
%% KeyParams = key_params()
296
%% Verified = boolean()
298
%% Description: Verifies the signature <Signature>.
299
%%--------------------------------------------------------------------
300
verify_signature(PlainText, DigestType, Signature, #'RSAPublicKey'{} = Key)
301
when is_binary(PlainText), is_binary(Signature), DigestType == sha;
303
pubkey_crypto:verify(DigestType, PlainText, Signature, Key, undefined).
305
verify_signature(PlainText, DigestType, Signature, #'RSAPublicKey'{} = Key,
307
when is_binary(PlainText), is_binary(Signature), DigestType == sha;
309
pubkey_crypto:verify(DigestType, PlainText, Signature, Key, KeyParams);
310
verify_signature(PlainText, sha, Signature, Key, #'Dss-Parms'{} = KeyParams)
311
when is_binary(PlainText), is_binary(Signature), is_integer(Key) ->
312
pubkey_crypto:verify(sha, PlainText, Signature, Key, KeyParams).
314
verify_signature(DerCert, Key, #'Dss-Parms'{} = KeyParams)
315
when is_binary(DerCert), is_integer(Key) ->
316
pubkey_cert:verify_signature(DerCert, Key, KeyParams);
317
verify_signature(DerCert, #'RSAPublicKey'{} = Key, KeyParams)
318
when is_binary(DerCert) ->
319
pubkey_cert:verify_signature(DerCert, Key, KeyParams).
321
%%--------------------------------------------------------------------
322
%%% Internal functions
323
%%--------------------------------------------------------------------
324
path_validation([], #path_validation_state{working_public_key_algorithm
328
working_public_key_parameters
330
valid_policy_tree = Tree,
331
acc_errors = AccErrors
333
{ok, {{Algorithm, PublicKey, PublicKeyParams}, Tree, AccErrors}};
335
path_validation([DerCert | Rest], ValidationState = #path_validation_state{
336
max_path_length = Len},
337
Fun, Verify) when Len >= 0 ->
339
try validate(DerCert,
340
ValidationState#path_validation_state{last_cert=Rest=:=[]},
342
#path_validation_state{} = NewValidationState ->
343
path_validation(Rest, NewValidationState, Fun, Verify)
349
path_validation(_, _, _, verify_peer) ->
350
{error, {bad_cert, max_path_length_reached}};
352
path_validation(_, #path_validation_state{working_public_key_algorithm
356
working_public_key_parameters
358
valid_policy_tree = Tree,
359
acc_errors = AccErrors
360
}, _, verify_none) ->
361
{ok, {{Algorithm, PublicKey, PublicKeyParams}, Tree, AccErrors}}.
363
validate(DerCert, #path_validation_state{working_issuer_name = Issuer,
364
working_public_key = Key,
365
working_public_key_parameters =
367
permitted_subtrees = Permit,
368
excluded_subtrees = Exclude,
370
user_state = UserState0,
371
acc_errors = AccErr0} =
372
ValidationState0, ValidateExtensionFun, Verify) ->
373
{ok, OtpCert} = pkix_decode_cert(DerCert, otp),
374
%% All validate functions will throw {bad_cert, Reason} if they
375
%% fail and Verify = true if Verify = false errors
376
%% will be accumulated in the validationstate
377
AccErr1 = pubkey_cert:validate_time(OtpCert, AccErr0, Verify),
379
pubkey_cert:validate_signature(OtpCert, DerCert, Key, KeyParams,
381
AccErr3 = pubkey_cert:validate_issuer(OtpCert, Issuer, AccErr2, Verify),
383
AccErr4 = pubkey_cert:validate_names(OtpCert, Permit, Exclude, Last,
386
pubkey_cert:validate_revoked_status(OtpCert, Verify, AccErr4),
388
{ValidationState1, UnknownExtensions0, AccErr6} =
389
pubkey_cert:validate_extensions(OtpCert, ValidationState0, Verify,
392
{UnknownExtensions, UserState, AccErr7} =
393
ValidateExtensionFun(UnknownExtensions0, UserState0, Verify, AccErr6),
395
%% Check that all critical extensions have been handled
397
pubkey_cert:validate_unknown_extensions(UnknownExtensions, AccErr7,
400
ValidationState1#path_validation_state{user_state = UserState,
401
acc_errors = AccErr},
402
pubkey_cert:prepare_for_next_cert(OtpCert, ValidationState).