3 * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
13 #include "crypto/crypto.h"
15 #include "tlsv1_cred.h"
18 struct tlsv1_credentials * tlsv1_cred_alloc(void)
20 struct tlsv1_credentials *cred;
21 cred = os_zalloc(sizeof(*cred));
26 void tlsv1_cred_free(struct tlsv1_credentials *cred)
31 x509_certificate_chain_free(cred->trusted_certs);
32 x509_certificate_chain_free(cred->cert);
33 crypto_private_key_free(cred->key);
40 static int tlsv1_add_cert_der(struct x509_certificate **chain,
41 const u8 *buf, size_t len)
43 struct x509_certificate *cert, *p;
46 cert = x509_certificate_parse(buf, len);
48 wpa_printf(MSG_INFO, "TLSv1: %s - failed to parse certificate",
56 if (p && x509_name_compare(&cert->subject, &p->issuer) == 0) {
58 * The new certificate is the issuer of the last certificate in
59 * the chain - add the new certificate to the end.
63 /* Add to the beginning of the chain */
68 x509_name_string(&cert->subject, name, sizeof(name));
69 wpa_printf(MSG_DEBUG, "TLSv1: Added certificate: %s", name);
75 static const char *pem_cert_begin = "-----BEGIN CERTIFICATE-----";
76 static const char *pem_cert_end = "-----END CERTIFICATE-----";
77 static const char *pem_key_begin = "-----BEGIN RSA PRIVATE KEY-----";
78 static const char *pem_key_end = "-----END RSA PRIVATE KEY-----";
79 static const char *pem_key2_begin = "-----BEGIN PRIVATE KEY-----";
80 static const char *pem_key2_end = "-----END PRIVATE KEY-----";
81 static const char *pem_key_enc_begin = "-----BEGIN ENCRYPTED PRIVATE KEY-----";
82 static const char *pem_key_enc_end = "-----END ENCRYPTED PRIVATE KEY-----";
85 static const u8 * search_tag(const char *tag, const u8 *buf, size_t len)
89 plen = os_strlen(tag);
93 for (i = 0; i < len - plen; i++) {
94 if (os_memcmp(buf + i, tag, plen) == 0)
102 static int tlsv1_add_cert(struct x509_certificate **chain,
103 const u8 *buf, size_t len)
109 pos = search_tag(pem_cert_begin, buf, len);
111 wpa_printf(MSG_DEBUG, "TLSv1: No PEM certificate tag found - "
112 "assume DER format");
113 return tlsv1_add_cert_der(chain, buf, len);
116 wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format certificate into "
120 pos += os_strlen(pem_cert_begin);
121 end = search_tag(pem_cert_end, pos, buf + len - pos);
123 wpa_printf(MSG_INFO, "TLSv1: Could not find PEM "
124 "certificate end tag (%s)", pem_cert_end);
128 der = base64_decode(pos, end - pos, &der_len);
130 wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM "
135 if (tlsv1_add_cert_der(chain, der, der_len) < 0) {
136 wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM "
137 "certificate after DER conversion");
144 end += os_strlen(pem_cert_end);
145 pos = search_tag(pem_cert_begin, end, buf + len - end);
152 static int tlsv1_set_cert_chain(struct x509_certificate **chain,
153 const char *cert, const u8 *cert_blob,
154 size_t cert_blob_len)
157 return tlsv1_add_cert(chain, cert_blob, cert_blob_len);
164 buf = (u8 *) os_readfile(cert, &len);
166 wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
171 ret = tlsv1_add_cert(chain, buf, len);
181 * tlsv1_set_ca_cert - Set trusted CA certificate(s)
182 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
183 * @cert: File or reference name for X.509 certificate in PEM or DER format
184 * @cert_blob: cert as inlined data or %NULL if not used
185 * @cert_blob_len: ca_cert_blob length
186 * @path: Path to CA certificates (not yet supported)
187 * Returns: 0 on success, -1 on failure
189 int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert,
190 const u8 *cert_blob, size_t cert_blob_len,
193 if (tlsv1_set_cert_chain(&cred->trusted_certs, cert,
194 cert_blob, cert_blob_len) < 0)
198 /* TODO: add support for reading number of certificate files */
199 wpa_printf(MSG_INFO, "TLSv1: Use of CA certificate directory "
200 "not yet supported");
209 * tlsv1_set_cert - Set certificate
210 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
211 * @cert: File or reference name for X.509 certificate in PEM or DER format
212 * @cert_blob: cert as inlined data or %NULL if not used
213 * @cert_blob_len: cert_blob length
214 * Returns: 0 on success, -1 on failure
216 int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert,
217 const u8 *cert_blob, size_t cert_blob_len)
219 return tlsv1_set_cert_chain(&cred->cert, cert,
220 cert_blob, cert_blob_len);
224 static struct crypto_private_key * tlsv1_set_key_pem(const u8 *key, size_t len)
229 struct crypto_private_key *pkey;
231 pos = search_tag(pem_key_begin, key, len);
233 pos = search_tag(pem_key2_begin, key, len);
236 pos += os_strlen(pem_key2_begin);
237 end = search_tag(pem_key2_end, pos, key + len - pos);
242 pos += os_strlen(pem_key_begin);
243 end = search_tag(pem_key_end, pos, key + len - pos);
246 pos2 = search_tag("Proc-Type: 4,ENCRYPTED", pos, end - pos);
248 wpa_printf(MSG_DEBUG, "TLSv1: Unsupported private key "
249 "format (Proc-Type/DEK-Info)");
254 der = base64_decode(pos, end - pos, &der_len);
257 pkey = crypto_private_key_import(der, der_len, NULL);
263 static struct crypto_private_key * tlsv1_set_key_enc_pem(const u8 *key,
270 struct crypto_private_key *pkey;
274 pos = search_tag(pem_key_enc_begin, key, len);
277 pos += os_strlen(pem_key_enc_begin);
278 end = search_tag(pem_key_enc_end, pos, key + len - pos);
282 der = base64_decode(pos, end - pos, &der_len);
285 pkey = crypto_private_key_import(der, der_len, passwd);
291 static int tlsv1_set_key(struct tlsv1_credentials *cred,
292 const u8 *key, size_t len, const char *passwd)
294 cred->key = crypto_private_key_import(key, len, passwd);
295 if (cred->key == NULL)
296 cred->key = tlsv1_set_key_pem(key, len);
297 if (cred->key == NULL)
298 cred->key = tlsv1_set_key_enc_pem(key, len, passwd);
299 if (cred->key == NULL) {
300 wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key");
308 * tlsv1_set_private_key - Set private key
309 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
310 * @private_key: File or reference name for the key in PEM or DER format
311 * @private_key_passwd: Passphrase for decrypted private key, %NULL if no
312 * passphrase is used.
313 * @private_key_blob: private_key as inlined data or %NULL if not used
314 * @private_key_blob_len: private_key_blob length
315 * Returns: 0 on success, -1 on failure
317 int tlsv1_set_private_key(struct tlsv1_credentials *cred,
318 const char *private_key,
319 const char *private_key_passwd,
320 const u8 *private_key_blob,
321 size_t private_key_blob_len)
323 crypto_private_key_free(cred->key);
326 if (private_key_blob)
327 return tlsv1_set_key(cred, private_key_blob,
328 private_key_blob_len,
336 buf = (u8 *) os_readfile(private_key, &len);
338 wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
343 ret = tlsv1_set_key(cred, buf, len, private_key_passwd);
352 static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred,
353 const u8 *dh, size_t len)
362 * DHParameter ::= SEQUENCE {
363 * prime INTEGER, -- p
365 * privateValueLength INTEGER OPTIONAL }
368 /* DHParamer ::= SEQUENCE */
369 if (asn1_get_next(pos, len, &hdr) < 0 ||
370 hdr.class != ASN1_CLASS_UNIVERSAL ||
371 hdr.tag != ASN1_TAG_SEQUENCE) {
372 wpa_printf(MSG_DEBUG, "DH: DH parameters did not start with a "
373 "valid SEQUENCE - found class %d tag 0x%x",
380 if (asn1_get_next(pos, end - pos, &hdr) < 0)
383 if (hdr.class != ASN1_CLASS_UNIVERSAL ||
384 hdr.tag != ASN1_TAG_INTEGER) {
385 wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for p; "
386 "class=%d tag=0x%x", hdr.class, hdr.tag);
390 wpa_hexdump(MSG_MSGDUMP, "DH: prime (p)", hdr.payload, hdr.length);
394 cred->dh_p = os_malloc(hdr.length);
395 if (cred->dh_p == NULL)
397 os_memcpy(cred->dh_p, hdr.payload, hdr.length);
398 cred->dh_p_len = hdr.length;
399 pos = hdr.payload + hdr.length;
402 if (asn1_get_next(pos, end - pos, &hdr) < 0)
405 if (hdr.class != ASN1_CLASS_UNIVERSAL ||
406 hdr.tag != ASN1_TAG_INTEGER) {
407 wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for g; "
408 "class=%d tag=0x%x", hdr.class, hdr.tag);
412 wpa_hexdump(MSG_MSGDUMP, "DH: base (g)", hdr.payload, hdr.length);
416 cred->dh_g = os_malloc(hdr.length);
417 if (cred->dh_g == NULL)
419 os_memcpy(cred->dh_g, hdr.payload, hdr.length);
420 cred->dh_g_len = hdr.length;
426 static const char *pem_dhparams_begin = "-----BEGIN DH PARAMETERS-----";
427 static const char *pem_dhparams_end = "-----END DH PARAMETERS-----";
430 static int tlsv1_set_dhparams_blob(struct tlsv1_credentials *cred,
431 const u8 *buf, size_t len)
437 pos = search_tag(pem_dhparams_begin, buf, len);
439 wpa_printf(MSG_DEBUG, "TLSv1: No PEM dhparams tag found - "
440 "assume DER format");
441 return tlsv1_set_dhparams_der(cred, buf, len);
444 wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format dhparams into DER "
447 pos += os_strlen(pem_dhparams_begin);
448 end = search_tag(pem_dhparams_end, pos, buf + len - pos);
450 wpa_printf(MSG_INFO, "TLSv1: Could not find PEM dhparams end "
451 "tag (%s)", pem_dhparams_end);
455 der = base64_decode(pos, end - pos, &der_len);
457 wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM dhparams");
461 if (tlsv1_set_dhparams_der(cred, der, der_len) < 0) {
462 wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM dhparams "
475 * tlsv1_set_dhparams - Set Diffie-Hellman parameters
476 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
477 * @dh_file: File or reference name for the DH params in PEM or DER format
478 * @dh_blob: DH params as inlined data or %NULL if not used
479 * @dh_blob_len: dh_blob length
480 * Returns: 0 on success, -1 on failure
482 int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file,
483 const u8 *dh_blob, size_t dh_blob_len)
486 return tlsv1_set_dhparams_blob(cred, dh_blob, dh_blob_len);
493 buf = (u8 *) os_readfile(dh_file, &len);
495 wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
500 ret = tlsv1_set_dhparams_blob(cred, buf, len);