1 /** 2 * Credentials Manager 3 * 4 * Copyright: 5 * (C) 2011,2012 Jack Lloyd 6 * (C) 2014-2015 Etienne Cimon 7 * 8 * License: 9 * Botan is released under the Simplified BSD License (see LICENSE.md) 10 */ 11 module botan.tls.credentials_manager; 12 13 import botan.constants; 14 static if (BOTAN_HAS_TLS): 15 import botan.cert.x509.x509cert; 16 import botan.cert.x509.certstor; 17 import botan.math.bigint.bigint; 18 import botan.pubkey.pk_keys; 19 import botan.algo_base.symkey; 20 import botan.tls.credentials_manager; 21 import botan.cert.x509.x509path; 22 import botan.utils.types; 23 24 /** 25 * Interface for a credentials manager. 26 * 27 * A type is a fairly static value that represents the general nature 28 * of the transaction occuring. Currently used values are "tls-client" 29 * and "tls-server". Context represents a hostname, email address, 30 * username, or other identifier. 31 */ 32 abstract class TLSCredentialsManager 33 { 34 public: 35 36 /** 37 * Return a list of the certificates of CAs that we trust in this 38 * type/context. 39 * 40 * Params: 41 * type = specifies the type of operation occuring 42 * 43 * context = specifies a context relative to type. For instance 44 * for type "tls-client", context specifies the servers name. 45 */ 46 abstract Vector!CertificateStore 47 trustedCertificateAuthorities(in string type, in string context) 48 { 49 return Vector!CertificateStore(); 50 } 51 52 /** 53 * Check the certificate chain is valid up to a trusted root, and 54 * optionally (if hostname != "") that the hostname given is 55 * consistent with the leaf certificate. 56 * 57 * This function should throw new an exception derived from 58 * $(D Exception) with an informative what() result if the 59 * certificate chain cannot be verified. 60 61 * Params: 62 * type = specifies the type of operation occuring 63 * purported_hostname = specifies the purported hostname 64 * cert_chain = specifies a certificate chain leading to a 65 * trusted root CA certificate. 66 */ 67 abstract void verifyCertificateChain(in string type, 68 in string purported_hostname, 69 const ref Vector!X509Certificate cert_chain) 70 { 71 if (cert_chain.empty) 72 throw new InvalidArgument("Certificate chain was empty"); 73 74 auto trusted_CAs = trustedCertificateAuthorities(type, purported_hostname); 75 76 PathValidationRestrictions restrictions; 77 78 auto result = x509PathValidate(cert_chain, 79 restrictions, 80 trusted_CAs); 81 82 if (!result.successfulValidation()) 83 throw new Exception("Certificate validation failure: " ~ result.resultString()); 84 85 if (!certInSomeStore(trusted_CAs, result.trustRoot())) 86 throw new Exception("Certificate chain roots in unknown/untrusted CA"); 87 88 if (purported_hostname != "" && !cert_chain[0].matchesDnsName(purported_hostname)) 89 throw new Exception("Certificate did not match hostname"); 90 } 91 92 /** 93 * Return a cert chain we can use, ordered from leaf to root, 94 * or else an empty vector. 95 * 96 * It is assumed that the caller can get the private key of the 97 * leaf with privateKeyFor 98 * 99 * Params: 100 * cert_key_types = specifies the key types desired ("RSA", 101 * "DSA", "ECDSA", etc), or empty if there 102 * is no preference by the caller. 103 * 104 * type = specifies the type of operation occuring 105 * 106 * context = specifies a context relative to type. 107 */ 108 abstract Vector!X509Certificate certChain(const ref Vector!string cert_key_types, 109 in string type, 110 in string context) 111 { 112 return Vector!X509Certificate(); 113 } 114 115 /// ditto 116 final Vector!X509Certificate certChain(T : string[])(auto ref T cert_key_types, in string type, in string context) 117 { 118 return certChain(Vector!string(cert_key_types), type, context); 119 } 120 121 /** 122 * Return a cert chain we can use, ordered from leaf to root, 123 * or else an empty vector. 124 * 125 * It is assumed that the caller can get the private key of the 126 * leaf with privateKeyFor 127 * 128 * Params: 129 * cert_key_type = specifies the type of key requested 130 * ("RSA", "DSA", "ECDSA", etc) 131 * 132 * type = specifies the type of operation occuring 133 * 134 * context = specifies a context relative to type. 135 */ 136 abstract Vector!X509Certificate certChainSingleType(in string cert_key_type, 137 in string type, 138 in string context) 139 { 140 Vector!string cert_types; 141 cert_types.pushBack(cert_key_type); 142 return certChain(cert_types, type, context); 143 } 144 145 /** 146 * 147 * Params: 148 * cert = as returned by cert_chain 149 * type = specifies the type of operation occuring 150 * context = specifies a context relative to type. 151 * 152 * Returns: private key associated with this certificate if we should 153 * use it with this context. 154 * 155 * Notes: this object should retain ownership of the returned key; 156 * it should not be deleted by the caller. 157 */ 158 abstract PrivateKey privateKeyFor(in X509Certificate cert, in string type, in string context) 159 { 160 return null; 161 } 162 163 /** 164 * Params: 165 * type = specifies the type of operation occuring 166 * context = specifies a context relative to type. 167 * Returns: true if we should attempt SRP authentication 168 */ 169 abstract bool attemptSrp(in string type, in string context) 170 { 171 return false; 172 } 173 174 /** 175 * Params: 176 * type = specifies the type of operation occuring 177 * context = specifies a context relative to type. 178 * Returns: identifier for client-side SRP auth, if available 179 for this type/context. Should return empty string 180 if password auth not desired/available. 181 */ 182 abstract string srpIdentifier(in string type, in string context) 183 { 184 return ""; 185 } 186 187 /** 188 * Params: 189 * type = specifies the type of operation occuring 190 * context = specifies a context relative to type. 191 * identifier = specifies what identifier we want the 192 * password for. This will be a value previously returned 193 * by srp_identifier. 194 * Returns: password for client-side SRP auth, if available 195 for this identifier/type/context. 196 */ 197 abstract string srpPassword(in string type, 198 in string context, 199 in string identifier) 200 { 201 return ""; 202 } 203 204 /** 205 * Retrieve SRP verifier parameters 206 */ 207 abstract bool srpVerifier(in string type, 208 in string context, 209 in string identifier, 210 ref string group_name, 211 ref BigInt verifier, 212 ref Vector!ubyte salt, 213 bool generate_fake_on_unknown) 214 { 215 return false; 216 } 217 218 /** 219 * Params: 220 * type = specifies the type of operation occuring 221 * context = specifies a context relative to type. 222 * Returns: the PSK identity hint for this type/context 223 */ 224 abstract string pskIdentityHint(in string type, in string context) 225 { 226 return ""; 227 } 228 229 /** 230 * Params: 231 * type = specifies the type of operation occuring 232 * context = specifies a context relative to type. 233 * identity_hint = was passed by the server (but may be empty) 234 * Returns: the PSK identity we want to use 235 */ 236 abstract string pskIdentity(in string type, in string context, in string identity_hint) 237 { 238 return ""; 239 } 240 241 /** 242 * Params: 243 * type = specifies the type of operation occuring 244 * context = specifies a context relative to type. 245 * identity = is a PSK identity previously returned by 246 psk_identity for the same type and context. 247 * Returns: the PSK used for identity, or throw new an exception if no 248 * key exists 249 */ 250 abstract SymmetricKey psk(in string type, in string context, in string identity) 251 { 252 throw new InternalError("No PSK set for identity " ~ identity); 253 } 254 } 255 256 bool certInSomeStore(const ref Vector!CertificateStore trusted_CAs, in X509Certificate trust_root) 257 { 258 foreach (const ref CertificateStore CAs; trusted_CAs[]) 259 if (CAs.certificateKnown(trust_root)) 260 return true; 261 return false; 262 }