3 * Copyright (c) 2006-2007, 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.
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-----";
75 static const u8 * search_tag(const char *tag, const u8 *buf, size_t len)
79 plen = os_strlen(tag);
83 for (i = 0; i < len - plen; i++) {
84 if (os_memcmp(buf + i, tag, plen) == 0)
92 static int tlsv1_add_cert(struct x509_certificate **chain,
93 const u8 *buf, size_t len)
99 pos = search_tag(pem_cert_begin, buf, len);
101 wpa_printf(MSG_DEBUG, "TLSv1: No PEM certificate tag found - "
102 "assume DER format");
103 return tlsv1_add_cert_der(chain, buf, len);
106 wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format certificate into "
110 pos += os_strlen(pem_cert_begin);
111 end = search_tag(pem_cert_end, pos, buf + len - pos);
113 wpa_printf(MSG_INFO, "TLSv1: Could not find PEM "
114 "certificate end tag (%s)", pem_cert_end);
118 der = base64_decode(pos, end - pos, &der_len);
120 wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM "
125 if (tlsv1_add_cert_der(chain, der, der_len) < 0) {
126 wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM "
127 "certificate after DER conversion");
134 end += os_strlen(pem_cert_end);
135 pos = search_tag(pem_cert_begin, end, buf + len - end);
142 static int tlsv1_set_cert_chain(struct x509_certificate **chain,
143 const char *cert, const u8 *cert_blob,
144 size_t cert_blob_len)
147 return tlsv1_add_cert(chain, cert_blob, cert_blob_len);
154 buf = (u8 *) os_readfile(cert, &len);
156 wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
161 ret = tlsv1_add_cert(chain, buf, len);
171 * tlsv1_set_ca_cert - Set trusted CA certificate(s)
172 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
173 * @cert: File or reference name for X.509 certificate in PEM or DER format
174 * @cert_blob: cert as inlined data or %NULL if not used
175 * @cert_blob_len: ca_cert_blob length
176 * @path: Path to CA certificates (not yet supported)
177 * Returns: 0 on success, -1 on failure
179 int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert,
180 const u8 *cert_blob, size_t cert_blob_len,
183 if (tlsv1_set_cert_chain(&cred->trusted_certs, cert,
184 cert_blob, cert_blob_len) < 0)
188 /* TODO: add support for reading number of certificate files */
189 wpa_printf(MSG_INFO, "TLSv1: Use of CA certificate directory "
190 "not yet supported");
199 * tlsv1_set_cert - Set certificate
200 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
201 * @cert: File or reference name for X.509 certificate in PEM or DER format
202 * @cert_blob: cert as inlined data or %NULL if not used
203 * @cert_blob_len: cert_blob length
204 * Returns: 0 on success, -1 on failure
206 int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert,
207 const u8 *cert_blob, size_t cert_blob_len)
209 return tlsv1_set_cert_chain(&cred->cert, cert,
210 cert_blob, cert_blob_len);
214 static int tlsv1_set_key_pem(struct tlsv1_credentials *cred,
215 const u8 *key, size_t len)
221 pos = search_tag(pem_key_begin, key, len);
225 pos += os_strlen(pem_key_begin);
226 end = search_tag(pem_key_end, pos, key + len - pos);
230 der = base64_decode(pos, end - pos, &der_len);
233 cred->key = crypto_private_key_import(der, der_len);
235 return cred->key ? 0 : -1;
239 static int tlsv1_set_key(struct tlsv1_credentials *cred,
240 const u8 *key, size_t len)
242 cred->key = crypto_private_key_import(key, len);
243 if (cred->key == NULL)
244 tlsv1_set_key_pem(cred, key, len);
245 if (cred->key == NULL) {
246 wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key");
254 * tlsv1_set_private_key - Set private key
255 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
256 * @private_key: File or reference name for the key in PEM or DER format
257 * @private_key_passwd: Passphrase for decrypted private key, %NULL if no
258 * passphrase is used.
259 * @private_key_blob: private_key as inlined data or %NULL if not used
260 * @private_key_blob_len: private_key_blob length
261 * Returns: 0 on success, -1 on failure
263 int tlsv1_set_private_key(struct tlsv1_credentials *cred,
264 const char *private_key,
265 const char *private_key_passwd,
266 const u8 *private_key_blob,
267 size_t private_key_blob_len)
269 crypto_private_key_free(cred->key);
272 if (private_key_blob)
273 return tlsv1_set_key(cred, private_key_blob,
274 private_key_blob_len);
281 buf = (u8 *) os_readfile(private_key, &len);
283 wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
288 ret = tlsv1_set_key(cred, buf, len);
297 static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred,
298 const u8 *dh, size_t len)
307 * DHParameter ::= SEQUENCE {
308 * prime INTEGER, -- p
310 * privateValueLength INTEGER OPTIONAL }
313 /* DHParamer ::= SEQUENCE */
314 if (asn1_get_next(pos, len, &hdr) < 0 ||
315 hdr.class != ASN1_CLASS_UNIVERSAL ||
316 hdr.tag != ASN1_TAG_SEQUENCE) {
317 wpa_printf(MSG_DEBUG, "DH: DH parameters did not start with a "
318 "valid SEQUENCE - found class %d tag 0x%x",
325 if (asn1_get_next(pos, end - pos, &hdr) < 0)
328 if (hdr.class != ASN1_CLASS_UNIVERSAL ||
329 hdr.tag != ASN1_TAG_INTEGER) {
330 wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for p; "
331 "class=%d tag=0x%x", hdr.class, hdr.tag);
335 wpa_hexdump(MSG_MSGDUMP, "DH: prime (p)", hdr.payload, hdr.length);
339 cred->dh_p = os_malloc(hdr.length);
340 if (cred->dh_p == NULL)
342 os_memcpy(cred->dh_p, hdr.payload, hdr.length);
343 cred->dh_p_len = hdr.length;
344 pos = hdr.payload + hdr.length;
347 if (asn1_get_next(pos, end - pos, &hdr) < 0)
350 if (hdr.class != ASN1_CLASS_UNIVERSAL ||
351 hdr.tag != ASN1_TAG_INTEGER) {
352 wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for g; "
353 "class=%d tag=0x%x", hdr.class, hdr.tag);
357 wpa_hexdump(MSG_MSGDUMP, "DH: base (g)", hdr.payload, hdr.length);
361 cred->dh_g = os_malloc(hdr.length);
362 if (cred->dh_g == NULL)
364 os_memcpy(cred->dh_g, hdr.payload, hdr.length);
365 cred->dh_g_len = hdr.length;
371 static const char *pem_dhparams_begin = "-----BEGIN DH PARAMETERS-----";
372 static const char *pem_dhparams_end = "-----END DH PARAMETERS-----";
375 static int tlsv1_set_dhparams_blob(struct tlsv1_credentials *cred,
376 const u8 *buf, size_t len)
382 pos = search_tag(pem_dhparams_begin, buf, len);
384 wpa_printf(MSG_DEBUG, "TLSv1: No PEM dhparams tag found - "
385 "assume DER format");
386 return tlsv1_set_dhparams_der(cred, buf, len);
389 wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format dhparams into DER "
392 pos += os_strlen(pem_dhparams_begin);
393 end = search_tag(pem_dhparams_end, pos, buf + len - pos);
395 wpa_printf(MSG_INFO, "TLSv1: Could not find PEM dhparams end "
396 "tag (%s)", pem_dhparams_end);
400 der = base64_decode(pos, end - pos, &der_len);
402 wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM dhparams");
406 if (tlsv1_set_dhparams_der(cred, der, der_len) < 0) {
407 wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM dhparams "
420 * tlsv1_set_dhparams - Set Diffie-Hellman parameters
421 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
422 * @dh_file: File or reference name for the DH params in PEM or DER format
423 * @dh_blob: DH params as inlined data or %NULL if not used
424 * @dh_blob_len: dh_blob length
425 * Returns: 0 on success, -1 on failure
427 int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file,
428 const u8 *dh_blob, size_t dh_blob_len)
431 return tlsv1_set_dhparams_blob(cred, dh_blob, dh_blob_len);
438 buf = (u8 *) os_readfile(dh_file, &len);
440 wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
445 ret = tlsv1_set_dhparams_blob(cred, buf, len);