$search
00001 /* 00002 * TLSv1 credentials 00003 * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation. 00008 * 00009 * Alternatively, this software may be distributed under the terms of BSD 00010 * license. 00011 * 00012 * See README and COPYING for more details. 00013 */ 00014 00015 #include "includes.h" 00016 00017 #include "common.h" 00018 #include "base64.h" 00019 #include "crypto/crypto.h" 00020 #include "x509v3.h" 00021 #include "tlsv1_cred.h" 00022 00023 00024 struct tlsv1_credentials * tlsv1_cred_alloc(void) 00025 { 00026 struct tlsv1_credentials *cred; 00027 cred = os_zalloc(sizeof(*cred)); 00028 return cred; 00029 } 00030 00031 00032 void tlsv1_cred_free(struct tlsv1_credentials *cred) 00033 { 00034 if (cred == NULL) 00035 return; 00036 00037 x509_certificate_chain_free(cred->trusted_certs); 00038 x509_certificate_chain_free(cred->cert); 00039 crypto_private_key_free(cred->key); 00040 os_free(cred->dh_p); 00041 os_free(cred->dh_g); 00042 os_free(cred); 00043 } 00044 00045 00046 static int tlsv1_add_cert_der(struct x509_certificate **chain, 00047 const u8 *buf, size_t len) 00048 { 00049 struct x509_certificate *cert; 00050 char name[128]; 00051 00052 cert = x509_certificate_parse(buf, len); 00053 if (cert == NULL) { 00054 wpa_printf(MSG_INFO, "TLSv1: %s - failed to parse certificate", 00055 __func__); 00056 return -1; 00057 } 00058 00059 cert->next = *chain; 00060 *chain = cert; 00061 00062 x509_name_string(&cert->subject, name, sizeof(name)); 00063 wpa_printf(MSG_DEBUG, "TLSv1: Added certificate: %s", name); 00064 00065 return 0; 00066 } 00067 00068 00069 static const char *pem_cert_begin = "-----BEGIN CERTIFICATE-----"; 00070 static const char *pem_cert_end = "-----END CERTIFICATE-----"; 00071 static const char *pem_key_begin = "-----BEGIN RSA PRIVATE KEY-----"; 00072 static const char *pem_key_end = "-----END RSA PRIVATE KEY-----"; 00073 static const char *pem_key2_begin = "-----BEGIN PRIVATE KEY-----"; 00074 static const char *pem_key2_end = "-----END PRIVATE KEY-----"; 00075 static const char *pem_key_enc_begin = "-----BEGIN ENCRYPTED PRIVATE KEY-----"; 00076 static const char *pem_key_enc_end = "-----END ENCRYPTED PRIVATE KEY-----"; 00077 00078 00079 static const u8 * search_tag(const char *tag, const u8 *buf, size_t len) 00080 { 00081 size_t i, plen; 00082 00083 plen = os_strlen(tag); 00084 if (len < plen) 00085 return NULL; 00086 00087 for (i = 0; i < len - plen; i++) { 00088 if (os_memcmp(buf + i, tag, plen) == 0) 00089 return buf + i; 00090 } 00091 00092 return NULL; 00093 } 00094 00095 00096 static int tlsv1_add_cert(struct x509_certificate **chain, 00097 const u8 *buf, size_t len) 00098 { 00099 const u8 *pos, *end; 00100 unsigned char *der; 00101 size_t der_len; 00102 00103 pos = search_tag(pem_cert_begin, buf, len); 00104 if (!pos) { 00105 wpa_printf(MSG_DEBUG, "TLSv1: No PEM certificate tag found - " 00106 "assume DER format"); 00107 return tlsv1_add_cert_der(chain, buf, len); 00108 } 00109 00110 wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format certificate into " 00111 "DER format"); 00112 00113 while (pos) { 00114 pos += os_strlen(pem_cert_begin); 00115 end = search_tag(pem_cert_end, pos, buf + len - pos); 00116 if (end == NULL) { 00117 wpa_printf(MSG_INFO, "TLSv1: Could not find PEM " 00118 "certificate end tag (%s)", pem_cert_end); 00119 return -1; 00120 } 00121 00122 der = base64_decode(pos, end - pos, &der_len); 00123 if (der == NULL) { 00124 wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM " 00125 "certificate"); 00126 return -1; 00127 } 00128 00129 if (tlsv1_add_cert_der(chain, der, der_len) < 0) { 00130 wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM " 00131 "certificate after DER conversion"); 00132 os_free(der); 00133 return -1; 00134 } 00135 00136 os_free(der); 00137 00138 end += os_strlen(pem_cert_end); 00139 pos = search_tag(pem_cert_begin, end, buf + len - end); 00140 } 00141 00142 return 0; 00143 } 00144 00145 00146 static int tlsv1_set_cert_chain(struct x509_certificate **chain, 00147 const char *cert, const u8 *cert_blob, 00148 size_t cert_blob_len) 00149 { 00150 if (cert_blob) 00151 return tlsv1_add_cert(chain, cert_blob, cert_blob_len); 00152 00153 if (cert) { 00154 u8 *buf; 00155 size_t len; 00156 int ret; 00157 00158 buf = (u8 *) os_readfile(cert, &len); 00159 if (buf == NULL) { 00160 wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'", 00161 cert); 00162 return -1; 00163 } 00164 00165 ret = tlsv1_add_cert(chain, buf, len); 00166 os_free(buf); 00167 return ret; 00168 } 00169 00170 return 0; 00171 } 00172 00173 00183 int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert, 00184 const u8 *cert_blob, size_t cert_blob_len, 00185 const char *path) 00186 { 00187 if (tlsv1_set_cert_chain(&cred->trusted_certs, cert, 00188 cert_blob, cert_blob_len) < 0) 00189 return -1; 00190 00191 if (path) { 00192 /* TODO: add support for reading number of certificate files */ 00193 wpa_printf(MSG_INFO, "TLSv1: Use of CA certificate directory " 00194 "not yet supported"); 00195 return -1; 00196 } 00197 00198 return 0; 00199 } 00200 00201 00210 int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert, 00211 const u8 *cert_blob, size_t cert_blob_len) 00212 { 00213 return tlsv1_set_cert_chain(&cred->cert, cert, 00214 cert_blob, cert_blob_len); 00215 } 00216 00217 00218 static struct crypto_private_key * tlsv1_set_key_pem(const u8 *key, size_t len) 00219 { 00220 const u8 *pos, *end; 00221 unsigned char *der; 00222 size_t der_len; 00223 struct crypto_private_key *pkey; 00224 00225 pos = search_tag(pem_key_begin, key, len); 00226 if (!pos) { 00227 pos = search_tag(pem_key2_begin, key, len); 00228 if (!pos) 00229 return NULL; 00230 pos += os_strlen(pem_key2_begin); 00231 end = search_tag(pem_key2_end, pos, key + len - pos); 00232 if (!end) 00233 return NULL; 00234 } else { 00235 pos += os_strlen(pem_key_begin); 00236 end = search_tag(pem_key_end, pos, key + len - pos); 00237 if (!end) 00238 return NULL; 00239 } 00240 00241 der = base64_decode(pos, end - pos, &der_len); 00242 if (!der) 00243 return NULL; 00244 pkey = crypto_private_key_import(der, der_len, NULL); 00245 os_free(der); 00246 return pkey; 00247 } 00248 00249 00250 static struct crypto_private_key * tlsv1_set_key_enc_pem(const u8 *key, 00251 size_t len, 00252 const char *passwd) 00253 { 00254 const u8 *pos, *end; 00255 unsigned char *der; 00256 size_t der_len; 00257 struct crypto_private_key *pkey; 00258 00259 if (passwd == NULL) 00260 return NULL; 00261 pos = search_tag(pem_key_enc_begin, key, len); 00262 if (!pos) 00263 return NULL; 00264 pos += os_strlen(pem_key_enc_begin); 00265 end = search_tag(pem_key_enc_end, pos, key + len - pos); 00266 if (!end) 00267 return NULL; 00268 00269 der = base64_decode(pos, end - pos, &der_len); 00270 if (!der) 00271 return NULL; 00272 pkey = crypto_private_key_import(der, der_len, passwd); 00273 os_free(der); 00274 return pkey; 00275 } 00276 00277 00278 static int tlsv1_set_key(struct tlsv1_credentials *cred, 00279 const u8 *key, size_t len, const char *passwd) 00280 { 00281 cred->key = crypto_private_key_import(key, len, passwd); 00282 if (cred->key == NULL) 00283 cred->key = tlsv1_set_key_pem(key, len); 00284 if (cred->key == NULL) 00285 cred->key = tlsv1_set_key_enc_pem(key, len, passwd); 00286 if (cred->key == NULL) { 00287 wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key"); 00288 return -1; 00289 } 00290 return 0; 00291 } 00292 00293 00304 int tlsv1_set_private_key(struct tlsv1_credentials *cred, 00305 const char *private_key, 00306 const char *private_key_passwd, 00307 const u8 *private_key_blob, 00308 size_t private_key_blob_len) 00309 { 00310 crypto_private_key_free(cred->key); 00311 cred->key = NULL; 00312 00313 if (private_key_blob) 00314 return tlsv1_set_key(cred, private_key_blob, 00315 private_key_blob_len, 00316 private_key_passwd); 00317 00318 if (private_key) { 00319 u8 *buf; 00320 size_t len; 00321 int ret; 00322 00323 buf = (u8 *) os_readfile(private_key, &len); 00324 if (buf == NULL) { 00325 wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'", 00326 private_key); 00327 return -1; 00328 } 00329 00330 ret = tlsv1_set_key(cred, buf, len, private_key_passwd); 00331 os_free(buf); 00332 return ret; 00333 } 00334 00335 return 0; 00336 } 00337 00338 00339 static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred, 00340 const u8 *dh, size_t len) 00341 { 00342 struct asn1_hdr hdr; 00343 const u8 *pos, *end; 00344 00345 pos = dh; 00346 end = dh + len; 00347 00348 /* 00349 * DHParameter ::= SEQUENCE { 00350 * prime INTEGER, -- p 00351 * base INTEGER, -- g 00352 * privateValueLength INTEGER OPTIONAL } 00353 */ 00354 00355 /* DHParamer ::= SEQUENCE */ 00356 if (asn1_get_next(pos, len, &hdr) < 0 || 00357 hdr.class != ASN1_CLASS_UNIVERSAL || 00358 hdr.tag != ASN1_TAG_SEQUENCE) { 00359 wpa_printf(MSG_DEBUG, "DH: DH parameters did not start with a " 00360 "valid SEQUENCE - found class %d tag 0x%x", 00361 hdr.class, hdr.tag); 00362 return -1; 00363 } 00364 pos = hdr.payload; 00365 00366 /* prime INTEGER */ 00367 if (asn1_get_next(pos, end - pos, &hdr) < 0) 00368 return -1; 00369 00370 if (hdr.class != ASN1_CLASS_UNIVERSAL || 00371 hdr.tag != ASN1_TAG_INTEGER) { 00372 wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for p; " 00373 "class=%d tag=0x%x", hdr.class, hdr.tag); 00374 return -1; 00375 } 00376 00377 wpa_hexdump(MSG_MSGDUMP, "DH: prime (p)", hdr.payload, hdr.length); 00378 if (hdr.length == 0) 00379 return -1; 00380 os_free(cred->dh_p); 00381 cred->dh_p = os_malloc(hdr.length); 00382 if (cred->dh_p == NULL) 00383 return -1; 00384 os_memcpy(cred->dh_p, hdr.payload, hdr.length); 00385 cred->dh_p_len = hdr.length; 00386 pos = hdr.payload + hdr.length; 00387 00388 /* base INTEGER */ 00389 if (asn1_get_next(pos, end - pos, &hdr) < 0) 00390 return -1; 00391 00392 if (hdr.class != ASN1_CLASS_UNIVERSAL || 00393 hdr.tag != ASN1_TAG_INTEGER) { 00394 wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for g; " 00395 "class=%d tag=0x%x", hdr.class, hdr.tag); 00396 return -1; 00397 } 00398 00399 wpa_hexdump(MSG_MSGDUMP, "DH: base (g)", hdr.payload, hdr.length); 00400 if (hdr.length == 0) 00401 return -1; 00402 os_free(cred->dh_g); 00403 cred->dh_g = os_malloc(hdr.length); 00404 if (cred->dh_g == NULL) 00405 return -1; 00406 os_memcpy(cred->dh_g, hdr.payload, hdr.length); 00407 cred->dh_g_len = hdr.length; 00408 00409 return 0; 00410 } 00411 00412 00413 static const char *pem_dhparams_begin = "-----BEGIN DH PARAMETERS-----"; 00414 static const char *pem_dhparams_end = "-----END DH PARAMETERS-----"; 00415 00416 00417 static int tlsv1_set_dhparams_blob(struct tlsv1_credentials *cred, 00418 const u8 *buf, size_t len) 00419 { 00420 const u8 *pos, *end; 00421 unsigned char *der; 00422 size_t der_len; 00423 00424 pos = search_tag(pem_dhparams_begin, buf, len); 00425 if (!pos) { 00426 wpa_printf(MSG_DEBUG, "TLSv1: No PEM dhparams tag found - " 00427 "assume DER format"); 00428 return tlsv1_set_dhparams_der(cred, buf, len); 00429 } 00430 00431 wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format dhparams into DER " 00432 "format"); 00433 00434 pos += os_strlen(pem_dhparams_begin); 00435 end = search_tag(pem_dhparams_end, pos, buf + len - pos); 00436 if (end == NULL) { 00437 wpa_printf(MSG_INFO, "TLSv1: Could not find PEM dhparams end " 00438 "tag (%s)", pem_dhparams_end); 00439 return -1; 00440 } 00441 00442 der = base64_decode(pos, end - pos, &der_len); 00443 if (der == NULL) { 00444 wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM dhparams"); 00445 return -1; 00446 } 00447 00448 if (tlsv1_set_dhparams_der(cred, der, der_len) < 0) { 00449 wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM dhparams " 00450 "DER conversion"); 00451 os_free(der); 00452 return -1; 00453 } 00454 00455 os_free(der); 00456 00457 return 0; 00458 } 00459 00460 00469 int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file, 00470 const u8 *dh_blob, size_t dh_blob_len) 00471 { 00472 if (dh_blob) 00473 return tlsv1_set_dhparams_blob(cred, dh_blob, dh_blob_len); 00474 00475 if (dh_file) { 00476 u8 *buf; 00477 size_t len; 00478 int ret; 00479 00480 buf = (u8 *) os_readfile(dh_file, &len); 00481 if (buf == NULL) { 00482 wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'", 00483 dh_file); 00484 return -1; 00485 } 00486 00487 ret = tlsv1_set_dhparams_blob(cred, buf, len); 00488 os_free(buf); 00489 return ret; 00490 } 00491 00492 return 0; 00493 }