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-----";
73 static const u8
* search_tag(const char *tag
, const u8
*buf
, size_t len
)
77 plen
= os_strlen(tag
);
81 for (i
= 0; i
< len
- plen
; i
++) {
82 if (os_memcmp(buf
+ i
, tag
, plen
) == 0)
90 static int tlsv1_add_cert(struct x509_certificate
**chain
,
91 const u8
*buf
, size_t len
)
97 pos
= search_tag(pem_cert_begin
, buf
, len
);
99 wpa_printf(MSG_DEBUG
, "TLSv1: No PEM certificate tag found - "
100 "assume DER format");
101 return tlsv1_add_cert_der(chain
, buf
, len
);
104 wpa_printf(MSG_DEBUG
, "TLSv1: Converting PEM format certificate into "
108 pos
+= os_strlen(pem_cert_begin
);
109 end
= search_tag(pem_cert_end
, pos
, buf
+ len
- pos
);
111 wpa_printf(MSG_INFO
, "TLSv1: Could not find PEM "
112 "certificate end tag (%s)", pem_cert_end
);
116 der
= base64_decode(pos
, end
- pos
, &der_len
);
118 wpa_printf(MSG_INFO
, "TLSv1: Could not decode PEM "
123 if (tlsv1_add_cert_der(chain
, der
, der_len
) < 0) {
124 wpa_printf(MSG_INFO
, "TLSv1: Failed to parse PEM "
125 "certificate after DER conversion");
132 end
+= os_strlen(pem_cert_end
);
133 pos
= search_tag(pem_cert_begin
, end
, buf
+ len
- end
);
140 static int tlsv1_set_cert_chain(struct x509_certificate
**chain
,
141 const char *cert
, const u8
*cert_blob
,
142 size_t cert_blob_len
)
145 return tlsv1_add_cert(chain
, cert_blob
, cert_blob_len
);
152 buf
= (u8
*) os_readfile(cert
, &len
);
154 wpa_printf(MSG_INFO
, "TLSv1: Failed to read '%s'",
159 ret
= tlsv1_add_cert(chain
, buf
, len
);
169 * tlsv1_set_ca_cert - Set trusted CA certificate(s)
170 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
171 * @cert: File or reference name for X.509 certificate in PEM or DER format
172 * @cert_blob: cert as inlined data or %NULL if not used
173 * @cert_blob_len: ca_cert_blob length
174 * @path: Path to CA certificates (not yet supported)
175 * Returns: 0 on success, -1 on failure
177 int tlsv1_set_ca_cert(struct tlsv1_credentials
*cred
, const char *cert
,
178 const u8
*cert_blob
, size_t cert_blob_len
,
181 if (tlsv1_set_cert_chain(&cred
->trusted_certs
, cert
,
182 cert_blob
, cert_blob_len
) < 0)
186 /* TODO: add support for reading number of certificate files */
187 wpa_printf(MSG_INFO
, "TLSv1: Use of CA certificate directory "
188 "not yet supported");
197 * tlsv1_set_cert - Set certificate
198 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
199 * @cert: File or reference name for X.509 certificate in PEM or DER format
200 * @cert_blob: cert as inlined data or %NULL if not used
201 * @cert_blob_len: cert_blob length
202 * Returns: 0 on success, -1 on failure
204 int tlsv1_set_cert(struct tlsv1_credentials
*cred
, const char *cert
,
205 const u8
*cert_blob
, size_t cert_blob_len
)
207 return tlsv1_set_cert_chain(&cred
->cert
, cert
,
208 cert_blob
, cert_blob_len
);
212 static int tlsv1_set_key(struct tlsv1_credentials
*cred
,
213 const u8
*key
, size_t len
)
215 cred
->key
= crypto_private_key_import(key
, len
);
216 if (cred
->key
== NULL
) {
217 wpa_printf(MSG_INFO
, "TLSv1: Failed to parse private key");
225 * tlsv1_set_private_key - Set private key
226 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
227 * @private_key: File or reference name for the key in PEM or DER format
228 * @private_key_passwd: Passphrase for decrypted private key, %NULL if no
229 * passphrase is used.
230 * @private_key_blob: private_key as inlined data or %NULL if not used
231 * @private_key_blob_len: private_key_blob length
232 * Returns: 0 on success, -1 on failure
234 int tlsv1_set_private_key(struct tlsv1_credentials
*cred
,
235 const char *private_key
,
236 const char *private_key_passwd
,
237 const u8
*private_key_blob
,
238 size_t private_key_blob_len
)
240 crypto_private_key_free(cred
->key
);
243 if (private_key_blob
)
244 return tlsv1_set_key(cred
, private_key_blob
,
245 private_key_blob_len
);
252 buf
= (u8
*) os_readfile(private_key
, &len
);
254 wpa_printf(MSG_INFO
, "TLSv1: Failed to read '%s'",
259 ret
= tlsv1_set_key(cred
, buf
, len
);
268 static int tlsv1_set_dhparams_der(struct tlsv1_credentials
*cred
,
269 const u8
*dh
, size_t len
)
278 * DHParameter ::= SEQUENCE {
279 * prime INTEGER, -- p
281 * privateValueLength INTEGER OPTIONAL }
284 /* DHParamer ::= SEQUENCE */
285 if (asn1_get_next(pos
, len
, &hdr
) < 0 ||
286 hdr
.class != ASN1_CLASS_UNIVERSAL
||
287 hdr
.tag
!= ASN1_TAG_SEQUENCE
) {
288 wpa_printf(MSG_DEBUG
, "DH: DH parameters did not start with a "
289 "valid SEQUENCE - found class %d tag 0x%x",
296 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0)
299 if (hdr
.class != ASN1_CLASS_UNIVERSAL
||
300 hdr
.tag
!= ASN1_TAG_INTEGER
) {
301 wpa_printf(MSG_DEBUG
, "DH: No INTEGER tag found for p; "
302 "class=%d tag=0x%x", hdr
.class, hdr
.tag
);
306 wpa_hexdump(MSG_MSGDUMP
, "DH: prime (p)", hdr
.payload
, hdr
.length
);
310 cred
->dh_p
= os_malloc(hdr
.length
);
311 if (cred
->dh_p
== NULL
)
313 os_memcpy(cred
->dh_p
, hdr
.payload
, hdr
.length
);
314 cred
->dh_p_len
= hdr
.length
;
315 pos
= hdr
.payload
+ hdr
.length
;
318 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0)
321 if (hdr
.class != ASN1_CLASS_UNIVERSAL
||
322 hdr
.tag
!= ASN1_TAG_INTEGER
) {
323 wpa_printf(MSG_DEBUG
, "DH: No INTEGER tag found for g; "
324 "class=%d tag=0x%x", hdr
.class, hdr
.tag
);
328 wpa_hexdump(MSG_MSGDUMP
, "DH: base (g)", hdr
.payload
, hdr
.length
);
332 cred
->dh_g
= os_malloc(hdr
.length
);
333 if (cred
->dh_g
== NULL
)
335 os_memcpy(cred
->dh_g
, hdr
.payload
, hdr
.length
);
336 cred
->dh_g_len
= hdr
.length
;
342 static const char *pem_dhparams_begin
= "-----BEGIN DH PARAMETERS-----";
343 static const char *pem_dhparams_end
= "-----END DH PARAMETERS-----";
346 static int tlsv1_set_dhparams_blob(struct tlsv1_credentials
*cred
,
347 const u8
*buf
, size_t len
)
353 pos
= search_tag(pem_dhparams_begin
, buf
, len
);
355 wpa_printf(MSG_DEBUG
, "TLSv1: No PEM dhparams tag found - "
356 "assume DER format");
357 return tlsv1_set_dhparams_der(cred
, buf
, len
);
360 wpa_printf(MSG_DEBUG
, "TLSv1: Converting PEM format dhparams into DER "
363 pos
+= os_strlen(pem_dhparams_begin
);
364 end
= search_tag(pem_dhparams_end
, pos
, buf
+ len
- pos
);
366 wpa_printf(MSG_INFO
, "TLSv1: Could not find PEM dhparams end "
367 "tag (%s)", pem_dhparams_end
);
371 der
= base64_decode(pos
, end
- pos
, &der_len
);
373 wpa_printf(MSG_INFO
, "TLSv1: Could not decode PEM dhparams");
377 if (tlsv1_set_dhparams_der(cred
, der
, der_len
) < 0) {
378 wpa_printf(MSG_INFO
, "TLSv1: Failed to parse PEM dhparams "
391 * tlsv1_set_dhparams - Set Diffie-Hellman parameters
392 * @cred: TLSv1 credentials from tlsv1_cred_alloc()
393 * @dh_file: File or reference name for the DH params in PEM or DER format
394 * @dh_blob: DH params as inlined data or %NULL if not used
395 * @dh_blob_len: dh_blob length
396 * Returns: 0 on success, -1 on failure
398 int tlsv1_set_dhparams(struct tlsv1_credentials
*cred
, const char *dh_file
,
399 const u8
*dh_blob
, size_t dh_blob_len
)
402 return tlsv1_set_dhparams_blob(cred
, dh_blob
, dh_blob_len
);
409 buf
= (u8
*) os_readfile(dh_file
, &len
);
411 wpa_printf(MSG_INFO
, "TLSv1: Failed to read '%s'",
416 ret
= tlsv1_set_dhparams_blob(cred
, buf
, len
);