1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2007-2020. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20 21%% 22 23-module(ssl_config). 24 25-include("ssl_internal.hrl"). 26-include("ssl_connection.hrl"). 27-include_lib("public_key/include/public_key.hrl"). 28 29-export([init/2]). 30 31init(#{erl_dist := ErlDist, 32 key := Key, 33 keyfile := KeyFile, 34 password := Password, 35 dh := DH, 36 dhfile := DHFile} = SslOpts, Role) -> 37 38 init_manager_name(ErlDist), 39 40 {ok, #{pem_cache := PemCache} = Config} 41 = init_certificates(SslOpts, Role), 42 PrivateKey = 43 init_private_key(PemCache, Key, KeyFile, Password, Role), 44 DHParams = init_diffie_hellman(PemCache, DH, DHFile, Role), 45 {ok, Config#{private_key => PrivateKey, dh_params => DHParams}}. 46 47init_manager_name(false) -> 48 put(ssl_manager, ssl_manager:name(normal)), 49 put(ssl_pem_cache, ssl_pem_cache:name(normal)); 50init_manager_name(true) -> 51 put(ssl_manager, ssl_manager:name(dist)), 52 put(ssl_pem_cache, ssl_pem_cache:name(dist)). 53 54init_certificates(#{cacerts := CaCerts, 55 cacertfile := CACertFile, 56 certfile := CertFile, 57 cert := Cert, 58 crl_cache := CRLCache 59 }, Role) -> 60 {ok, Config} = 61 try 62 Certs = case CaCerts of 63 undefined -> 64 CACertFile; 65 _ -> 66 {der, CaCerts} 67 end, 68 {ok,_} = ssl_manager:connection_init(Certs, Role, CRLCache) 69 catch 70 _:Reason -> 71 file_error(CACertFile, {cacertfile, Reason}) 72 end, 73 init_certificates(Cert, Config, CertFile, Role). 74 75init_certificates(undefined, Config, <<>>, _) -> 76 {ok, Config#{own_certificate => undefined}}; 77 78init_certificates(undefined, #{pem_cache := PemCache} = Config, CertFile, client) -> 79 try 80 %% Ignoring potential proxy-certificates see: 81 %% http://dev.globus.org/wiki/Security/ProxyFileFormat 82 [OwnCert|_] = ssl_certificate:file_to_certificats(CertFile, PemCache), 83 {ok, Config#{own_certificate => OwnCert}} 84 catch _Error:_Reason -> 85 {ok, Config#{own_certificate => undefined}} 86 end; 87 88init_certificates(undefined, #{pem_cache := PemCache} = Config, CertFile, server) -> 89 try 90 [OwnCert|_] = ssl_certificate:file_to_certificats(CertFile, PemCache), 91 {ok, Config#{own_certificate => OwnCert}} 92 catch 93 _:Reason -> 94 file_error(CertFile, {certfile, Reason}) 95 end; 96init_certificates(Cert, Config, _, _) -> 97 {ok, Config#{own_certificate => Cert}}. 98init_private_key(_, #{algorithm := Alg} = Key, _, _Password, _Client) when Alg == ecdsa; 99 Alg == rsa; 100 Alg == dss -> 101 case maps:is_key(engine, Key) andalso maps:is_key(key_id, Key) of 102 true -> 103 Key; 104 false -> 105 throw({key, {invalid_key_id, Key}}) 106 end; 107init_private_key(_, undefined, <<>>, _Password, _Client) -> 108 undefined; 109init_private_key(DbHandle, undefined, KeyFile, Password, _) -> 110 try 111 {ok, List} = ssl_manager:cache_pem_file(KeyFile, DbHandle), 112 [PemEntry] = [PemEntry || PemEntry = {PKey, _ , _} <- List, 113 PKey =:= 'RSAPrivateKey' orelse 114 PKey =:= 'DSAPrivateKey' orelse 115 PKey =:= 'ECPrivateKey' orelse 116 PKey =:= 'PrivateKeyInfo' 117 ], 118 private_key(public_key:pem_entry_decode(PemEntry, Password)) 119 catch 120 _:Reason -> 121 file_error(KeyFile, {keyfile, Reason}) 122 end; 123 124init_private_key(_,{Asn1Type, PrivateKey},_,_,_) -> 125 private_key(init_private_key(Asn1Type, PrivateKey)). 126 127init_private_key(Asn1Type, PrivateKey) -> 128 public_key:der_decode(Asn1Type, PrivateKey). 129 130private_key(#'PrivateKeyInfo'{privateKeyAlgorithm = 131 #'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?'rsaEncryption'}, 132 privateKey = Key}) -> 133 public_key:der_decode('RSAPrivateKey', iolist_to_binary(Key)); 134 135private_key(#'PrivateKeyInfo'{privateKeyAlgorithm = 136 #'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?'id-dsa'}, 137 privateKey = Key}) -> 138 public_key:der_decode('DSAPrivateKey', iolist_to_binary(Key)); 139private_key(#'PrivateKeyInfo'{privateKeyAlgorithm = 140 #'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?'id-ecPublicKey', 141 parameters = {asn1_OPENTYPE, Parameters}}, 142 privateKey = Key}) -> 143 ECKey = public_key:der_decode('ECPrivateKey', iolist_to_binary(Key)), 144 ECParameters = public_key:der_decode('EcpkParameters', Parameters), 145 ECKey#'ECPrivateKey'{parameters = ECParameters}; 146private_key(Key) -> 147 Key. 148 149-spec(file_error(_,_) -> no_return()). 150file_error(File, Throw) -> 151 case Throw of 152 {Opt,{badmatch, {error, {badmatch, Error}}}} -> 153 throw({options, {Opt, binary_to_list(File), Error}}); 154 {Opt, {badmatch, Error}} -> 155 throw({options, {Opt, binary_to_list(File), Error}}); 156 _ -> 157 throw(Throw) 158 end. 159 160init_diffie_hellman(_,Params, _,_) when is_binary(Params)-> 161 public_key:der_decode('DHParameter', Params); 162init_diffie_hellman(_,_,_, client) -> 163 undefined; 164init_diffie_hellman(_,_,undefined, _) -> 165 ?DEFAULT_DIFFIE_HELLMAN_PARAMS; 166init_diffie_hellman(DbHandle,_, DHParamFile, server) -> 167 try 168 {ok, List} = ssl_manager:cache_pem_file(DHParamFile,DbHandle), 169 case [Entry || Entry = {'DHParameter', _ , _} <- List] of 170 [Entry] -> 171 public_key:pem_entry_decode(Entry); 172 [] -> 173 ?DEFAULT_DIFFIE_HELLMAN_PARAMS 174 end 175 catch 176 _:Reason -> 177 file_error(DHParamFile, {dhfile, Reason}) 178 end. 179