3 * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
19 #include "crypto/crypto.h"
21 #include "tlsv1_cred.h"
24 struct tlsv1_credentials * tlsv1_cred_alloc(void)
26 struct tlsv1_credentials *cred;
27 cred = os_zalloc(sizeof(*cred));
32 void tlsv1_cred_free(struct tlsv1_credentials *cred)
37 x509_certificate_chain_free(cred->trusted_certs);
38 x509_certificate_chain_free(cred->cert);
39 crypto_private_key_free(cred->key);
46 static int tlsv1_add_cert_der(struct x509_certificate **chain,
47 const u8 *buf, size_t len)
49 struct x509_certificate *cert;
52 cert = x509_certificate_parse(buf, len);
54 wpa_printf(MSG_INFO, "TLSv1: %s - failed to parse certificate",
62 x509_name_string(&cert->subject, name, sizeof(name));
63 wpa_printf(MSG_DEBUG, "TLSv1: Added certificate: %s", name);
69 static const char *pem_cert_begin = "-----BEGIN CERTIFICATE-----";
70 static const char *pem_cert_end = "-----END CERTIFICATE-----";
71 static const char *pem_key_begin = "-----BEGIN RSA PRIVATE KEY-----";
72 static const char *pem_key_end = "-----END RSA PRIVATE KEY-----";
73 static const char *pem_key2_begin = "-----BEGIN PRIVATE KEY-----";
74 static const char *pem_key2_end = "-----END PRIVATE KEY-----";
75 static const char *pem_key_enc_begin = "-----BEGIN ENCRYPTED PRIVATE KEY-----";
76 static const char *pem_key_enc_end = "-----END ENCRYPTED PRIVATE KEY-----";
79 static const u8 * search_tag(const char *tag, const u8 *buf, size_t len)
83 plen = os_strlen(tag);
87 for (i = 0; i < len - plen; i++) {
88 if (os_memcmp(buf + i, tag, plen) == 0)
96 static int tlsv1_add_cert(struct x509_certificate **chain,
97 const u8 *buf, size_t len)
103 pos = search_tag(pem_cert_begin, buf, len);
105 wpa_printf(MSG_DEBUG, "TLSv1: No PEM certificate tag found - "
106 "assume DER format");
107 return tlsv1_add_cert_der(chain, buf, len);
110 wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format certificate into "
114 pos += os_strlen(pem_cert_begin);
115 end = search_tag(pem_cert_end, pos, buf + len - pos);
117 wpa_printf(MSG_INFO, "TLSv1: Could not find PEM "
118 "certificate end tag (%s)", pem_cert_end);
122 der = base64_decode(pos, end - pos, &der_len);
124 wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM "
129 if (tlsv1_add_cert_der(chain, der, der_len) < 0) {
130 wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM "
131 "certificate after DER conversion");
138 end += os_strlen(pem_cert_end);
139 pos = search_tag(pem_cert_begin, end, buf + len - end);
146 static int tlsv1_set_cert_chain(struct x509_certificate **chain,
147 const char *cert, const u8 *cert_blob,
148 size_t cert_blob_len)
151 return tlsv1_add_cert(chain, cert_blob, cert_blob_len);
158 buf = (u8 *) os_readfile(cert, &len);
160 wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
165 ret = tlsv1_add_cert(chain, buf, len);
175 * tlsv1_set_ca_cert - Set trusted CA certificate(s)
176 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
177 * @cert: File or reference name for X.509 certificate in PEM or DER format
178 * @cert_blob: cert as inlined data or %NULL if not used
179 * @cert_blob_len: ca_cert_blob length
180 * @path: Path to CA certificates (not yet supported)
181 * Returns: 0 on success, -1 on failure
183 int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert,
184 const u8 *cert_blob, size_t cert_blob_len,
187 if (tlsv1_set_cert_chain(&cred->trusted_certs, cert,
188 cert_blob, cert_blob_len) < 0)
192 /* TODO: add support for reading number of certificate files */
193 wpa_printf(MSG_INFO, "TLSv1: Use of CA certificate directory "
194 "not yet supported");
203 * tlsv1_set_cert - Set certificate
204 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
205 * @cert: File or reference name for X.509 certificate in PEM or DER format
206 * @cert_blob: cert as inlined data or %NULL if not used
207 * @cert_blob_len: cert_blob length
208 * Returns: 0 on success, -1 on failure
210 int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert,
211 const u8 *cert_blob, size_t cert_blob_len)
213 return tlsv1_set_cert_chain(&cred->cert, cert,
214 cert_blob, cert_blob_len);
218 static struct crypto_private_key * tlsv1_set_key_pem(const u8 *key, size_t len)
223 struct crypto_private_key *pkey;
225 pos = search_tag(pem_key_begin, key, len);
227 pos = search_tag(pem_key2_begin, key, len);
230 pos += os_strlen(pem_key2_begin);
231 end = search_tag(pem_key2_end, pos, key + len - pos);
235 pos += os_strlen(pem_key_begin);
236 end = search_tag(pem_key_end, pos, key + len - pos);
241 der = base64_decode(pos, end - pos, &der_len);
244 pkey = crypto_private_key_import(der, der_len, NULL);
250 static struct crypto_private_key * tlsv1_set_key_enc_pem(const u8 *key,
257 struct crypto_private_key *pkey;
261 pos = search_tag(pem_key_enc_begin, key, len);
264 pos += os_strlen(pem_key_enc_begin);
265 end = search_tag(pem_key_enc_end, pos, key + len - pos);
269 der = base64_decode(pos, end - pos, &der_len);
272 pkey = crypto_private_key_import(der, der_len, passwd);
278 static int tlsv1_set_key(struct tlsv1_credentials *cred,
279 const u8 *key, size_t len, const char *passwd)
281 cred->key = crypto_private_key_import(key, len, passwd);
282 if (cred->key == NULL)
283 cred->key = tlsv1_set_key_pem(key, len);
284 if (cred->key == NULL)
285 cred->key = tlsv1_set_key_enc_pem(key, len, passwd);
286 if (cred->key == NULL) {
287 wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key");
295 * tlsv1_set_private_key - Set private key
296 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
297 * @private_key: File or reference name for the key in PEM or DER format
298 * @private_key_passwd: Passphrase for decrypted private key, %NULL if no
299 * passphrase is used.
300 * @private_key_blob: private_key as inlined data or %NULL if not used
301 * @private_key_blob_len: private_key_blob length
302 * Returns: 0 on success, -1 on failure
304 int tlsv1_set_private_key(struct tlsv1_credentials *cred,
305 const char *private_key,
306 const char *private_key_passwd,
307 const u8 *private_key_blob,
308 size_t private_key_blob_len)
310 crypto_private_key_free(cred->key);
313 if (private_key_blob)
314 return tlsv1_set_key(cred, private_key_blob,
315 private_key_blob_len,
323 buf = (u8 *) os_readfile(private_key, &len);
325 wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
330 ret = tlsv1_set_key(cred, buf, len, private_key_passwd);
339 static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred,
340 const u8 *dh, size_t len)
349 * DHParameter ::= SEQUENCE {
350 * prime INTEGER, -- p
352 * privateValueLength INTEGER OPTIONAL }
355 /* DHParamer ::= SEQUENCE */
356 if (asn1_get_next(pos, len, &hdr) < 0 ||
357 hdr.class != ASN1_CLASS_UNIVERSAL ||
358 hdr.tag != ASN1_TAG_SEQUENCE) {
359 wpa_printf(MSG_DEBUG, "DH: DH parameters did not start with a "
360 "valid SEQUENCE - found class %d tag 0x%x",
367 if (asn1_get_next(pos, end - pos, &hdr) < 0)
370 if (hdr.class != ASN1_CLASS_UNIVERSAL ||
371 hdr.tag != ASN1_TAG_INTEGER) {
372 wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for p; "
373 "class=%d tag=0x%x", hdr.class, hdr.tag);
377 wpa_hexdump(MSG_MSGDUMP, "DH: prime (p)", hdr.payload, hdr.length);
381 cred->dh_p = os_malloc(hdr.length);
382 if (cred->dh_p == NULL)
384 os_memcpy(cred->dh_p, hdr.payload, hdr.length);
385 cred->dh_p_len = hdr.length;
386 pos = hdr.payload + hdr.length;
389 if (asn1_get_next(pos, end - pos, &hdr) < 0)
392 if (hdr.class != ASN1_CLASS_UNIVERSAL ||
393 hdr.tag != ASN1_TAG_INTEGER) {
394 wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for g; "
395 "class=%d tag=0x%x", hdr.class, hdr.tag);
399 wpa_hexdump(MSG_MSGDUMP, "DH: base (g)", hdr.payload, hdr.length);
403 cred->dh_g = os_malloc(hdr.length);
404 if (cred->dh_g == NULL)
406 os_memcpy(cred->dh_g, hdr.payload, hdr.length);
407 cred->dh_g_len = hdr.length;
413 static const char *pem_dhparams_begin = "-----BEGIN DH PARAMETERS-----";
414 static const char *pem_dhparams_end = "-----END DH PARAMETERS-----";
417 static int tlsv1_set_dhparams_blob(struct tlsv1_credentials *cred,
418 const u8 *buf, size_t len)
424 pos = search_tag(pem_dhparams_begin, buf, len);
426 wpa_printf(MSG_DEBUG, "TLSv1: No PEM dhparams tag found - "
427 "assume DER format");
428 return tlsv1_set_dhparams_der(cred, buf, len);
431 wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format dhparams into DER "
434 pos += os_strlen(pem_dhparams_begin);
435 end = search_tag(pem_dhparams_end, pos, buf + len - pos);
437 wpa_printf(MSG_INFO, "TLSv1: Could not find PEM dhparams end "
438 "tag (%s)", pem_dhparams_end);
442 der = base64_decode(pos, end - pos, &der_len);
444 wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM dhparams");
448 if (tlsv1_set_dhparams_der(cred, der, der_len) < 0) {
449 wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM dhparams "
462 * tlsv1_set_dhparams - Set Diffie-Hellman parameters
463 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
464 * @dh_file: File or reference name for the DH params in PEM or DER format
465 * @dh_blob: DH params as inlined data or %NULL if not used
466 * @dh_blob_len: dh_blob length
467 * Returns: 0 on success, -1 on failure
469 int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file,
470 const u8 *dh_blob, size_t dh_blob_len)
473 return tlsv1_set_dhparams_blob(cred, dh_blob, dh_blob_len);
480 buf = (u8 *) os_readfile(dh_file, &len);
482 wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
487 ret = tlsv1_set_dhparams_blob(cred, buf, len);