18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * TLSv1 credentials
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "base64.h"
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/crypto.h"
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "x509v3.h"
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "tlsv1_cred.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct tlsv1_credentials * tlsv1_cred_alloc(void)
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tlsv1_credentials *cred;
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cred = os_zalloc(sizeof(*cred));
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return cred;
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid tlsv1_cred_free(struct tlsv1_credentials *cred)
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cred == NULL)
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	x509_certificate_chain_free(cred->trusted_certs);
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	x509_certificate_chain_free(cred->cert);
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	crypto_private_key_free(cred->key);
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(cred->dh_p);
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(cred->dh_g);
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(cred);
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int tlsv1_add_cert_der(struct x509_certificate **chain,
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      const u8 *buf, size_t len)
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct x509_certificate *cert, *p;
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char name[128];
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cert = x509_certificate_parse(buf, len);
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cert == NULL) {
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "TLSv1: %s - failed to parse certificate",
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__);
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	p = *chain;
541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	while (p && p->next)
551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		p = p->next;
561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (p && x509_name_compare(&cert->subject, &p->issuer) == 0) {
571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		/*
581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		 * The new certificate is the issuer of the last certificate in
591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		 * the chain - add the new certificate to the end.
601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		 */
611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		p->next = cert;
621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	} else {
631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		/* Add to the beginning of the chain */
641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		cert->next = *chain;
651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		*chain = cert;
661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	x509_name_string(&cert->subject, name, sizeof(name));
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "TLSv1: Added certificate: %s", name);
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const char *pem_cert_begin = "-----BEGIN CERTIFICATE-----";
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const char *pem_cert_end = "-----END CERTIFICATE-----";
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const char *pem_key_begin = "-----BEGIN RSA PRIVATE KEY-----";
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const char *pem_key_end = "-----END RSA PRIVATE KEY-----";
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const char *pem_key2_begin = "-----BEGIN PRIVATE KEY-----";
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const char *pem_key2_end = "-----END PRIVATE KEY-----";
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const char *pem_key_enc_begin = "-----BEGIN ENCRYPTED PRIVATE KEY-----";
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const char *pem_key_enc_end = "-----END ENCRYPTED PRIVATE KEY-----";
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const u8 * search_tag(const char *tag, const u8 *buf, size_t len)
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i, plen;
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	plen = os_strlen(tag);
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len < plen)
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < len - plen; i++) {
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_memcmp(buf + i, tag, plen) == 0)
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return buf + i;
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int tlsv1_add_cert(struct x509_certificate **chain,
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  const u8 *buf, size_t len)
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pos, *end;
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned char *der;
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t der_len;
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = search_tag(pem_cert_begin, buf, len);
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!pos) {
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "TLSv1: No PEM certificate tag found - "
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "assume DER format");
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return tlsv1_add_cert_der(chain, buf, len);
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format certificate into "
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "DER format");
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (pos) {
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += os_strlen(pem_cert_begin);
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		end = search_tag(pem_cert_end, pos, buf + len - pos);
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (end == NULL) {
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "TLSv1: Could not find PEM "
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "certificate end tag (%s)", pem_cert_end);
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		der = base64_decode(pos, end - pos, &der_len);
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (der == NULL) {
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM "
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "certificate");
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (tlsv1_add_cert_der(chain, der, der_len) < 0) {
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM "
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "certificate after DER conversion");
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_free(der);
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(der);
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		end += os_strlen(pem_cert_end);
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos = search_tag(pem_cert_begin, end, buf + len - end);
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int tlsv1_set_cert_chain(struct x509_certificate **chain,
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				const char *cert, const u8 *cert_blob,
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				size_t cert_blob_len)
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cert_blob)
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return tlsv1_add_cert(chain, cert_blob, cert_blob_len);
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cert) {
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		u8 *buf;
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		size_t len;
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int ret;
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		buf = (u8 *) os_readfile(cert, &len);
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (buf == NULL) {
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   cert);
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = tlsv1_add_cert(chain, buf, len);
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(buf);
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return ret;
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * tlsv1_set_ca_cert - Set trusted CA certificate(s)
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @cred: TLSv1 credentials from tlsv1_cred_alloc()
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @cert: File or reference name for X.509 certificate in PEM or DER format
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @cert_blob: cert as inlined data or %NULL if not used
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @cert_blob_len: ca_cert_blob length
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @path: Path to CA certificates (not yet supported)
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert,
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      const u8 *cert_blob, size_t cert_blob_len,
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      const char *path)
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tlsv1_set_cert_chain(&cred->trusted_certs, cert,
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 cert_blob, cert_blob_len) < 0)
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (path) {
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* TODO: add support for reading number of certificate files */
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "TLSv1: Use of CA certificate directory "
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "not yet supported");
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * tlsv1_set_cert - Set certificate
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @cred: TLSv1 credentials from tlsv1_cred_alloc()
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @cert: File or reference name for X.509 certificate in PEM or DER format
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @cert_blob: cert as inlined data or %NULL if not used
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @cert_blob_len: cert_blob length
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert,
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   const u8 *cert_blob, size_t cert_blob_len)
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return tlsv1_set_cert_chain(&cred->cert, cert,
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    cert_blob, cert_blob_len);
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct crypto_private_key * tlsv1_set_key_pem(const u8 *key, size_t len)
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pos, *end;
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned char *der;
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t der_len;
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct crypto_private_key *pkey;
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = search_tag(pem_key_begin, key, len);
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!pos) {
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos = search_tag(pem_key2_begin, key, len);
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!pos)
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NULL;
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += os_strlen(pem_key2_begin);
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		end = search_tag(pem_key2_end, pos, key + len - pos);
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!end)
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NULL;
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
2411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		const u8 *pos2;
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += os_strlen(pem_key_begin);
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		end = search_tag(pem_key_end, pos, key + len - pos);
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!end)
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NULL;
2461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		pos2 = search_tag("Proc-Type: 4,ENCRYPTED", pos, end - pos);
2471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (pos2) {
2481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_printf(MSG_DEBUG, "TLSv1: Unsupported private key "
2491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   "format (Proc-Type/DEK-Info)");
2501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			return NULL;
2511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	der = base64_decode(pos, end - pos, &der_len);
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!der)
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pkey = crypto_private_key_import(der, der_len, NULL);
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(der);
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return pkey;
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct crypto_private_key * tlsv1_set_key_enc_pem(const u8 *key,
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt							 size_t len,
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt							 const char *passwd)
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pos, *end;
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned char *der;
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t der_len;
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct crypto_private_key *pkey;
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (passwd == NULL)
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = search_tag(pem_key_enc_begin, key, len);
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!pos)
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += os_strlen(pem_key_enc_begin);
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = search_tag(pem_key_enc_end, pos, key + len - pos);
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!end)
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	der = base64_decode(pos, end - pos, &der_len);
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!der)
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pkey = crypto_private_key_import(der, der_len, passwd);
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(der);
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return pkey;
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int tlsv1_set_key(struct tlsv1_credentials *cred,
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 const u8 *key, size_t len, const char *passwd)
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cred->key = crypto_private_key_import(key, len, passwd);
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cred->key == NULL)
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cred->key = tlsv1_set_key_pem(key, len);
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cred->key == NULL)
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cred->key = tlsv1_set_key_enc_pem(key, len, passwd);
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cred->key == NULL) {
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key");
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * tlsv1_set_private_key - Set private key
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @cred: TLSv1 credentials from tlsv1_cred_alloc()
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @private_key: File or reference name for the key in PEM or DER format
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @private_key_passwd: Passphrase for decrypted private key, %NULL if no
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * passphrase is used.
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @private_key_blob: private_key as inlined data or %NULL if not used
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @private_key_blob_len: private_key_blob length
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tlsv1_set_private_key(struct tlsv1_credentials *cred,
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  const char *private_key,
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  const char *private_key_passwd,
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  const u8 *private_key_blob,
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  size_t private_key_blob_len)
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	crypto_private_key_free(cred->key);
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cred->key = NULL;
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (private_key_blob)
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return tlsv1_set_key(cred, private_key_blob,
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     private_key_blob_len,
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     private_key_passwd);
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (private_key) {
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		u8 *buf;
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		size_t len;
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int ret;
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		buf = (u8 *) os_readfile(private_key, &len);
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (buf == NULL) {
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   private_key);
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = tlsv1_set_key(cred, buf, len, private_key_passwd);
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(buf);
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return ret;
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred,
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  const u8 *dh, size_t len)
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct asn1_hdr hdr;
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pos, *end;
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = dh;
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = dh + len;
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * DHParameter ::= SEQUENCE {
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 *   prime INTEGER, -- p
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 *   base INTEGER, -- g
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 *   privateValueLength INTEGER OPTIONAL }
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* DHParamer ::= SEQUENCE */
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (asn1_get_next(pos, len, &hdr) < 0 ||
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    hdr.class != ASN1_CLASS_UNIVERSAL ||
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    hdr.tag != ASN1_TAG_SEQUENCE) {
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "DH: DH parameters did not start with a "
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "valid SEQUENCE - found class %d tag 0x%x",
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   hdr.class, hdr.tag);
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = hdr.payload;
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* prime INTEGER */
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (asn1_get_next(pos, end - pos, &hdr) < 0)
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hdr.class != ASN1_CLASS_UNIVERSAL ||
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    hdr.tag != ASN1_TAG_INTEGER) {
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for p; "
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "class=%d tag=0x%x", hdr.class, hdr.tag);
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_MSGDUMP, "DH: prime (p)", hdr.payload, hdr.length);
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hdr.length == 0)
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(cred->dh_p);
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cred->dh_p = os_malloc(hdr.length);
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cred->dh_p == NULL)
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(cred->dh_p, hdr.payload, hdr.length);
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cred->dh_p_len = hdr.length;
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = hdr.payload + hdr.length;
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* base INTEGER */
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (asn1_get_next(pos, end - pos, &hdr) < 0)
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hdr.class != ASN1_CLASS_UNIVERSAL ||
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    hdr.tag != ASN1_TAG_INTEGER) {
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for g; "
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "class=%d tag=0x%x", hdr.class, hdr.tag);
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_MSGDUMP, "DH: base (g)", hdr.payload, hdr.length);
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hdr.length == 0)
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(cred->dh_g);
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cred->dh_g = os_malloc(hdr.length);
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cred->dh_g == NULL)
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(cred->dh_g, hdr.payload, hdr.length);
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cred->dh_g_len = hdr.length;
4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const char *pem_dhparams_begin = "-----BEGIN DH PARAMETERS-----";
4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const char *pem_dhparams_end = "-----END DH PARAMETERS-----";
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int tlsv1_set_dhparams_blob(struct tlsv1_credentials *cred,
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   const u8 *buf, size_t len)
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pos, *end;
4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned char *der;
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t der_len;
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = search_tag(pem_dhparams_begin, buf, len);
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!pos) {
4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "TLSv1: No PEM dhparams tag found - "
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "assume DER format");
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return tlsv1_set_dhparams_der(cred, buf, len);
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format dhparams into DER "
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "format");
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += os_strlen(pem_dhparams_begin);
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = search_tag(pem_dhparams_end, pos, buf + len - pos);
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (end == NULL) {
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "TLSv1: Could not find PEM dhparams end "
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "tag (%s)", pem_dhparams_end);
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	der = base64_decode(pos, end - pos, &der_len);
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (der == NULL) {
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM dhparams");
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tlsv1_set_dhparams_der(cred, der, der_len) < 0) {
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM dhparams "
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "DER conversion");
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(der);
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(der);
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * tlsv1_set_dhparams - Set Diffie-Hellman parameters
4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @cred: TLSv1 credentials from tlsv1_cred_alloc()
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @dh_file: File or reference name for the DH params in PEM or DER format
4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @dh_blob: DH params as inlined data or %NULL if not used
4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @dh_blob_len: dh_blob length
4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file,
4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       const u8 *dh_blob, size_t dh_blob_len)
4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (dh_blob)
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return tlsv1_set_dhparams_blob(cred, dh_blob, dh_blob_len);
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (dh_file) {
4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		u8 *buf;
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		size_t len;
4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int ret;
4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		buf = (u8 *) os_readfile(dh_file, &len);
4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (buf == NULL) {
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   dh_file);
4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = tlsv1_set_dhparams_blob(cred, buf, len);
5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(buf);
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return ret;
5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
507