tlsv1_cred.c
Go to the documentation of this file.
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 }


wpa_supplicant_node
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Apr 24 2014 15:33:21