Merge pull request #671 from mrdeep1/rpk_check

RPK: Support verification of peer certificate
This commit is contained in:
obgm authored and GitHub committed 2021-05-20 12:57:19 +02:00
commit a8df0adf2f
3 files changed
+126 -83

No files matched your search

+5 -6
View File
@@ -1251,18 +1251,18 @@ setup_pki(coap_context_t *ctx) {
dtls_pki.check_cert_revocation = 1;
dtls_pki.allow_no_crl = 1;
dtls_pki.allow_expired_crl = 1;
dtls_pki.validate_cn_call_back = verify_cn_callback;
dtls_pki.cn_call_back_arg = NULL;
dtls_pki.validate_sni_call_back = NULL;
dtls_pki.sni_call_back_arg = NULL;
}
else if (is_rpk_not_cert) {
dtls_pki.verify_peer_cert = verify_peer_cert;
}
dtls_pki.is_rpk_not_cert = is_rpk_not_cert;
dtls_pki.validate_cn_call_back = verify_cn_callback;
if ((uri.host.length == 3 && memcmp(uri.host.s, "::1", 3) != 0) ||
(uri.host.length == 9 && memcmp(uri.host.s, "127.0.0.1", 9) != 0))
memcpy(client_sni, uri.host.s, min(uri.host.length, sizeof(client_sni)-1));
else
memcpy(client_sni, "localhost", 9);
dtls_pki.is_rpk_not_cert = is_rpk_not_cert;
dtls_pki.client_sni = client_sni;
if ((key_file && strncasecmp (key_file, "pkcs11:", 7) == 0) ||
(cert_file && strncasecmp (cert_file, "pkcs11:", 7) == 0) ||
@@ -1528,7 +1528,6 @@ main(int argc, char **argv) {
case 'M':
cert_file = optarg;
is_rpk_not_cert = 1;
verify_peer_cert = 0; /* This does not work for RPK */
break;
case 'O':
cmdline_option(optarg);
+69 -71
View File
@@ -89,6 +89,11 @@ static char *root_ca_file = NULL; /* List of trusted Root CAs in PEM */
static int use_pem_buf = 0; /* Map these cert/key files into memory to test
PEM_BUF logic if set */
static int is_rpk_not_cert = 0; /* Cert is RPK if set */
/* Used to hold initial PEM_BUF setup */
static uint8_t *cert_mem_base = NULL; /* certificate and private key in PEM_BUF */
static uint8_t *key_mem_base = NULL; /* private key in PEM_BUF */
static uint8_t *ca_mem_base = NULL; /* CA for cert checking in PEM_BUF */
/* Used for verify_pki_sni_callback PEM_BUF temporary holding */
static uint8_t *cert_mem = NULL; /* certificate and private key in PEM_BUF */
static uint8_t *key_mem = NULL; /* private key in PEM_BUF */
static uint8_t *ca_mem = NULL; /* CA for cert checking in PEM_BUF */
@@ -1835,40 +1840,53 @@ static uint8_t *read_file_mem(const char* file, size_t *length) {
return buf;
}
static void
update_pki_key(coap_dtls_key_t *dtls_key, const char *key_name,
const char *cert_name, const char *ca_name) {;
memset (dtls_key, 0, sizeof(*dtls_key));
if ((key_name && strncasecmp (key_name, "pkcs11:", 7) == 0) ||
(cert_name && strncasecmp (cert_name, "pkcs11:", 7) == 0) ||
(ca_name && strncasecmp (ca_name, "pkcs11:", 7) == 0)) {
dtls_key->key_type = COAP_PKI_KEY_PKCS11;
dtls_key->key.pkcs11.public_cert = cert_name;
dtls_key->key.pkcs11.private_key = key_name ? key_name : cert_name;
dtls_key->key.pkcs11.ca = ca_name;
dtls_key->key.pkcs11.user_pin = pkcs11_pin;
}
else if (!use_pem_buf && !is_rpk_not_cert) {
dtls_key->key_type = COAP_PKI_KEY_PEM;
dtls_key->key.pem.public_cert = cert_name;
dtls_key->key.pem.private_key = key_name ? key_name : cert_name;
dtls_key->key.pem.ca_file = ca_name;
}
else {
/* Map file into memory */
coap_free(ca_mem);
coap_free(cert_mem);
coap_free(key_mem);
ca_mem = read_file_mem(ca_name, &ca_mem_len);
cert_mem = read_file_mem(cert_name, &cert_mem_len);
key_mem = read_file_mem(key_name, &key_mem_len);
dtls_key->key_type = COAP_PKI_KEY_PEM_BUF;
dtls_key->key.pem_buf.ca_cert = ca_mem;
dtls_key->key.pem_buf.public_cert = cert_mem;
dtls_key->key.pem_buf.private_key = key_mem ? key_mem : cert_mem;
dtls_key->key.pem_buf.ca_cert_len = ca_mem_len;
dtls_key->key.pem_buf.public_cert_len = cert_mem_len;
dtls_key->key.pem_buf.private_key_len = key_mem ?
key_mem_len : cert_mem_len;
}
}
static coap_dtls_key_t *
verify_pki_sni_callback(const char *sni,
void *arg COAP_UNUSED
) {
static coap_dtls_key_t dtls_key;
/* Preset with the defined keys */
memset (&dtls_key, 0, sizeof(dtls_key));
if (!use_pem_buf) {
if ((key_file && strncasecmp (key_file, "pkcs11:", 7) == 0) ||
(cert_file && strncasecmp (cert_file, "pkcs11:", 7) == 0) ||
(ca_file && strncasecmp (ca_file, "pkcs11:", 7) == 0)) {
dtls_key.key_type = COAP_PKI_KEY_PKCS11;
dtls_key.key.pkcs11.public_cert = cert_file;
dtls_key.key.pkcs11.private_key = key_file ? key_file : cert_file;
dtls_key.key.pkcs11.ca = ca_file;
dtls_key.key.pkcs11.user_pin = pkcs11_pin;
}
else {
dtls_key.key_type = COAP_PKI_KEY_PEM;
dtls_key.key.pem.public_cert = cert_file;
dtls_key.key.pem.private_key = key_file ? key_file : cert_file;
dtls_key.key.pem.ca_file = ca_file;
}
}
else {
dtls_key.key_type = COAP_PKI_KEY_PEM_BUF;
dtls_key.key.pem_buf.ca_cert = ca_mem;
dtls_key.key.pem_buf.public_cert = cert_mem;
dtls_key.key.pem_buf.private_key = cert_mem;
dtls_key.key.pem_buf.ca_cert_len = ca_mem_len;
dtls_key.key.pem_buf.public_cert_len = cert_mem_len;
dtls_key.key.pem_buf.private_key_len = cert_mem_len;
}
update_pki_key(&dtls_key, key_file, cert_file, ca_file);
if (sni[0]) {
size_t i;
coap_log(LOG_INFO, "SNI '%s' requested\n", sni);
@@ -1878,10 +1896,9 @@ verify_pki_sni_callback(const char *sni,
coap_log(LOG_INFO, "Switching to using cert '%s' + ca '%s'\n",
valid_pki_snis.pki_sni_list[i].new_cert,
valid_pki_snis.pki_sni_list[i].new_ca);
dtls_key.key_type = COAP_PKI_KEY_PEM;
dtls_key.key.pem.public_cert = valid_pki_snis.pki_sni_list[i].new_cert;
dtls_key.key.pem.private_key = valid_pki_snis.pki_sni_list[i].new_cert;
dtls_key.key.pem.ca_file = valid_pki_snis.pki_sni_list[i].new_ca;
update_pki_key(&dtls_key, valid_pki_snis.pki_sni_list[i].new_cert,
valid_pki_snis.pki_sni_list[i].new_cert,
valid_pki_snis.pki_sni_list[i].new_ca);
break;
}
}
@@ -2008,50 +2025,29 @@ setup_pki(coap_context_t *ctx, coap_dtls_role_t role, char *client_sni) {
dtls_pki.check_cert_revocation = 1;
dtls_pki.allow_no_crl = 1;
dtls_pki.allow_expired_crl = 1;
dtls_pki.validate_cn_call_back = verify_cn_callback;
dtls_pki.cn_call_back_arg = (void*)role;
dtls_pki.validate_sni_call_back = role == COAP_DTLS_ROLE_SERVER ?
verify_pki_sni_callback : NULL;
dtls_pki.sni_call_back_arg = NULL;
}
dtls_pki.is_rpk_not_cert = is_rpk_not_cert;
else if (is_rpk_not_cert) {
dtls_pki.verify_peer_cert = verify_peer_cert;
}
dtls_pki.is_rpk_not_cert = is_rpk_not_cert;
dtls_pki.validate_cn_call_back = verify_cn_callback;
dtls_pki.cn_call_back_arg = (void*)role;
dtls_pki.validate_sni_call_back = role == COAP_DTLS_ROLE_SERVER ?
verify_pki_sni_callback : NULL;
dtls_pki.sni_call_back_arg = NULL;
if (role == COAP_DTLS_ROLE_CLIENT) {
dtls_pki.client_sni = client_sni;
}
if ((key_file && strncasecmp (key_file, "pkcs11:", 7) == 0) ||
(cert_file && strncasecmp (cert_file, "pkcs11:", 7) == 0) ||
(ca_file && strncasecmp (ca_file, "pkcs11:", 7) == 0)) {
dtls_pki.pki_key.key_type = COAP_PKI_KEY_PKCS11;
dtls_pki.pki_key.key.pkcs11.public_cert = cert_file;
dtls_pki.pki_key.key.pkcs11.private_key = key_file ?
key_file : cert_file;
dtls_pki.pki_key.key.pkcs11.ca = ca_file;
dtls_pki.pki_key.key.pkcs11.user_pin = pkcs11_pin;
}
else if (!use_pem_buf && !is_rpk_not_cert) {
dtls_pki.pki_key.key_type = COAP_PKI_KEY_PEM;
dtls_pki.pki_key.key.pem.public_cert = cert_file;
dtls_pki.pki_key.key.pem.private_key = key_file ? key_file : cert_file;
dtls_pki.pki_key.key.pem.ca_file = ca_file;
}
else {
/* Map file into memory */
if (ca_mem == 0 && cert_mem == 0 && key_mem == 0) {
ca_mem = read_file_mem(ca_file, &ca_mem_len);
cert_mem = read_file_mem(cert_file, &cert_mem_len);
key_mem = read_file_mem(key_file, &key_mem_len);
}
dtls_pki.pki_key.key_type = COAP_PKI_KEY_PEM_BUF;
dtls_pki.pki_key.key.pem_buf.ca_cert = ca_mem;
dtls_pki.pki_key.key.pem_buf.public_cert = cert_mem;
dtls_pki.pki_key.key.pem_buf.private_key = key_mem ? key_mem : cert_mem;
dtls_pki.pki_key.key.pem_buf.ca_cert_len = ca_mem_len;
dtls_pki.pki_key.key.pem_buf.public_cert_len = cert_mem_len;
dtls_pki.pki_key.key.pem_buf.private_key_len = key_mem ?
key_mem_len : cert_mem_len;
}
update_pki_key(&dtls_pki.pki_key, key_file, cert_file, ca_file);
/* Need to keep base initialization copies of any COAP_PKI_KEY_PEM_BUF */
ca_mem_base = ca_mem;
cert_mem_base = cert_mem;
key_mem_base = key_mem;
ca_mem = NULL;
cert_mem = NULL;
key_mem = NULL;
return &dtls_pki;
}
@@ -2678,7 +2674,6 @@ main(int argc, char **argv) {
case 'M':
cert_file = optarg;
is_rpk_not_cert = 1;
verify_peer_cert = 0; /* This does not work for RPK */
break;
case 'n':
verify_peer_cert = 0;
@@ -2850,6 +2845,9 @@ main(int argc, char **argv) {
coap_free(ca_mem);
coap_free(cert_mem);
coap_free(key_mem);
coap_free(ca_mem_base);
coap_free(cert_mem_base);
coap_free(key_mem_base);
for (i = 0; i < valid_psk_snis.count; i++) {
free(valid_psk_snis.psk_sni_list[i].sni_match);
coap_delete_bin_const(valid_psk_snis.psk_sni_list[i].new_hint);
+52 -6
View File
@@ -55,6 +55,7 @@
#include <gnutls/dtls.h>
#include <gnutls/pkcs11.h>
#include <gnutls/crypto.h>
#include <gnutls/abstract.h>
#include <unistd.h>
#if (GNUTLS_VERSION_NUMBER >= 0x030606)
#define COAP_GNUTLS_KEY_RPK GNUTLS_KEY_DIGITAL_SIGNATURE | \
@@ -629,8 +630,6 @@ static gnutls_certificate_type_t get_san_or_cn(gnutls_session_t g_session,
#else /* < 3.6.6 */
cert_info->certificate_type = gnutls_certificate_type_get(g_session);
#endif /* < 3.6.6 */
if (cert_info->certificate_type != GNUTLS_CRT_X509)
return cert_info->certificate_type;
cert_info->san_or_cn = NULL;
@@ -640,6 +639,9 @@ static gnutls_certificate_type_t get_san_or_cn(gnutls_session_t g_session,
return GNUTLS_CRT_UNKNOWN;
}
if (cert_info->certificate_type != GNUTLS_CRT_X509)
return cert_info->certificate_type;
G_CHECK(gnutls_x509_crt_init(&cert), "gnutls_x509_crt_init");
/* Interested only in first cert in chain */
@@ -700,6 +702,42 @@ fail:
cert_info.san_or_cn : "?")
#endif /* GNUTLS_VERSION_NUMBER < 0x030606 */
#if (GNUTLS_VERSION_NUMBER >= 0x030606)
static int
check_rpk_cert(coap_gnutls_context_t *g_context,
coap_gnutls_certificate_info_t *cert_info,
coap_session_t *c_session) {
int ret;
if (g_context->setup_data.validate_cn_call_back) {
gnutls_pcert_st pcert;
uint8_t der[2048];
size_t size;
G_CHECK(gnutls_pcert_import_rawpk_raw(&pcert, &cert_info->cert_list[0],
GNUTLS_X509_FMT_DER, 0, 0),
"gnutls_pcert_import_rawpk_raw");
size = sizeof(der);
G_CHECK(gnutls_pubkey_export(pcert.pubkey, GNUTLS_X509_FMT_DER, der, &size),
"gnutls_pubkey_export");
gnutls_pcert_deinit(&pcert);
if (!g_context->setup_data.validate_cn_call_back(COAP_DTLS_RPK_CERT_CN,
der,
size,
c_session,
0,
1,
g_context->setup_data.cn_call_back_arg)) {
return 0;
}
}
return 1;
fail:
return 0;
}
#endif /* >= 3.6.6 */
/*
* return 0 failed
* 1 passed
@@ -722,9 +760,16 @@ static int cert_verify_gnutls(gnutls_session_t g_session)
cert_type = get_san_or_cn(g_session, &cert_info);
#if (GNUTLS_VERSION_NUMBER >= 0x030606)
if (cert_type == GNUTLS_CRT_RAW)
goto finish;
if (!check_rpk_cert(g_context, &cert_info, c_session)) {
alert = GNUTLS_A_ACCESS_DENIED;
goto fail;
}
return 1;
#endif /* >= 3.6.6 */
if (cert_info.cert_list_size == 0 && !g_context->setup_data.verify_peer_cert)
return 1;
G_CHECK(gnutls_certificate_verify_peers(g_session, NULL, 0, &status),
"gnutls_certificate_verify_peers");
@@ -859,9 +904,6 @@ static int cert_verify_gnutls(gnutls_session_t g_session)
}
}
#if (GNUTLS_VERSION_NUMBER >= 0x030606)
finish:
#endif /* >= 3.6.6 */
if (cert_info.san_or_cn)
gnutls_free(cert_info.san_or_cn);
@@ -1841,6 +1883,10 @@ setup_server_ssl_session(coap_session_t *c_session, coap_gnutls_env_t *g_env)
gnutls_certificate_server_set_request(g_env->g_session,
GNUTLS_CERT_REQUIRE);
}
else if (setup_data->is_rpk_not_cert) {
gnutls_certificate_server_set_request(g_env->g_session,
GNUTLS_CERT_REQUEST);
}
else {
gnutls_certificate_server_set_request(g_env->g_session,
GNUTLS_CERT_IGNORE);