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
);