Commit 76fd81e0 authored by Kishen Maloor's avatar Kishen Maloor

oc_pki & oc_cred: updates and fixes

oc_pki:
-Install cert chains in PEM instead of DER.

oc_cred:
-Removed special logic for provisioning DER chains. The use of the DER
format has been deprecated in the OCF Security Specification.
-Fixed logic for locating a role credential with/without an authority.
-Fixed oc_sec_clear_creds() to remove all cred entries (including any
pre-installed PKI chains) upon every DELETE or RESET. PKI chains may
be reinstalled later from the factory_presets callback.
-Fixed logic while receiving an identity cert to check for a
match of public key from the certificate with the device's own
public key. This would enable the provisioning of cred entries
with/without the device's own UUID being filled into that entry's
"subjectuuid".
Previously there was logic that checked for a match of the
cred entry's "subjectuuid" and the device's own deviceuuid. This
required OBTs to provision a cred object with the correct "subjectuuid".
This change has instead made it more flexible for OBTs by removing
any reliance on "subjectuuid".
-Fixed add_new_cred() to parse role certificates when provisioned
to a Client's /oic/sec/cred and extract the roleid for storage
inside the cred entry.

Change-Id: I59a1f11272bc546e4d21af37742658f4403d1449
Signed-off-by: Kishen Maloor's avatarKishen Maloor <kishen.maloor@intel.com>
parent 0c585b7d
......@@ -109,16 +109,20 @@ oc_sec_find_role_cred(const char *role, const char *authority)
/* Checking only the 0th logical device for Clients */
oc_sec_cred_t *creds = (oc_sec_cred_t *)oc_list_head(devices[0].creds);
size_t role_len = strlen(role);
size_t authority_len = strlen(authority);
size_t authority_len = 0;
if (authority) {
authority_len = strlen(authority);
}
while (creds) {
if (creds->credtype == OC_CREDTYPE_CERT &&
creds->credusage == OC_CREDUSAGE_ROLE_CERT) {
if ((role_len == oc_string_len(creds->role.role)) &&
(memcmp(role, oc_string(creds->role.role), role_len) == 0)) {
if ((authority_len == oc_string_len(creds->role.authority)) &&
(memcmp(authority, oc_string(creds->role.authority),
authority_len) == 0)) {
if (authority_len == 0) {
return creds;
} else if ((authority_len == oc_string_len(creds->role.authority)) &&
(memcmp(authority, oc_string(creds->role.authority),
authority_len) == 0)) {
return creds;
}
}
......@@ -189,23 +193,6 @@ oc_sec_remove_cred_by_credid(int credid, size_t device)
static void
oc_sec_clear_creds(size_t device)
{
oc_sec_cred_t *cred = oc_list_head(devices[device].creds), *next;
while (cred != NULL) {
next = cred->next;
#ifdef OC_PKI
if (cred->credusage != OC_CREDUSAGE_MFG_TRUSTCA &&
cred->credusage != OC_CREDUSAGE_MFG_CERT)
#endif /* OC_PKI */
{
oc_sec_remove_cred(cred, device);
}
cred = next;
}
}
static void
oc_sec_free_creds(size_t device)
{
oc_sec_cred_t *cred = oc_list_head(devices[device].creds), *next;
while (cred != NULL) {
......@@ -228,7 +215,7 @@ oc_sec_cred_free(void)
{
size_t device;
for (device = 0; device < oc_core_get_num_devices(); device++) {
oc_sec_free_creds(device);
oc_sec_clear_creds(device);
}
#ifdef OC_DYNAMIC_ALLOCATION
if (devices) {
......@@ -310,15 +297,17 @@ oc_sec_add_new_cred(size_t device, bool roles_resource, oc_tls_peer_t *client,
(void)roles_resource;
#ifdef OC_PKI
uint8_t public_key[OC_KEYPAIR_PUBKEY_SIZE] = { 0 };
if (credtype == OC_CREDTYPE_CERT &&
oc_certs_parse_public_key(publicdata, publicdata_size + 1, public_key) <
0) {
return -1;
}
if (roles_resource) {
if (credusage != OC_CREDUSAGE_ROLE_CERT) {
return -1;
}
uint8_t public_key[OC_KEYPAIR_PUBKEY_SIZE];
if (oc_certs_parse_public_key(publicdata, publicdata_size + 1, public_key) <
0) {
return -1;
}
if (memcmp(public_key, client->public_key, OC_KEYPAIR_PUBKEY_SIZE) != 0) {
return -1;
}
......@@ -346,14 +335,13 @@ oc_sec_add_new_cred(size_t device, bool roles_resource, oc_tls_peer_t *client,
oc_ecdsa_keypair_t *kp = NULL;
if (credusage == OC_CREDUSAGE_IDENTITY_CERT && privatedata_size == 0) {
oc_uuid_t *uuid = oc_core_get_device_id(device);
if (memcmp(uuid->id, subject.id, 16) != 0) {
return -1;
}
kp = oc_sec_get_ecdsa_keypair(device);
if (!kp) {
return -1;
}
if (memcmp(kp->public_key, public_key, OC_KEYPAIR_PUBKEY_SIZE) != 0) {
return -1;
}
}
#endif /* OC_PKI */
......@@ -369,9 +357,6 @@ oc_sec_add_new_cred(size_t device, bool roles_resource, oc_tls_peer_t *client,
#endif /* OC_PKI */
}
#ifdef OC_PKI
oc_sec_cred_t *chain = NULL;
#endif /* OC_PKI */
oc_sec_cred_t *cred = NULL;
if (!roles_resource) {
do {
......@@ -392,14 +377,6 @@ oc_sec_add_new_cred(size_t device, bool roles_resource, oc_tls_peer_t *client,
memcmp(publicdata, oc_string(cred->publicdata.data),
publicdata_size) == 0) {
return cred->credid;
} else if (cred->credusage != OC_CREDUSAGE_TRUSTCA &&
cred->credusage != OC_CREDUSAGE_MFG_TRUSTCA) {
/* Trying to record a new cert in a cert chain via a
* separate cred entry. Store a pointer to the existing
* cred entry for linking to two below.
*/
chain = cred;
break;
}
}
#endif /* OC_PKI */
......@@ -435,27 +412,12 @@ oc_sec_add_new_cred(size_t device, bool roles_resource, oc_tls_peer_t *client,
}
#ifdef OC_PKI
if (chain) {
if (oc_string_len(chain->privatedata.data) > 0) {
chain->chain = cred;
cred->child = chain;
} else if (privatedata_size > 0) {
cred->chain = chain;
chain->child = cred;
} else {
/* Cannot find the leaf certificate among two certificates carrying
* the same subjectuuid. This contradicts the three tiered certificate
* hierarchy and is hence an error.
*/
oc_sec_remove_cred(cred, device);
return -1;
}
}
if (roles_resource) {
if (credusage == OC_CREDUSAGE_ROLE_CERT) {
if (oc_certs_parse_role_certificate(publicdata, publicdata_size + 1, cred,
roles_resource) < 0) {
oc_sec_free_role(cred, client);
if (roles_resource) {
oc_sec_free_role(cred, client);
}
return -1;
}
}
......@@ -1101,7 +1063,7 @@ delete_cred(oc_request_t *request, oc_interface_mask_t iface_mask, void *data)
}
} else {
if (!roles_resource) {
oc_sec_free_creds(request->resource->device);
oc_sec_clear_creds(request->resource->device);
}
#ifdef OC_PKI
else {
......
/*
// Copyright (c) 2018 Intel Corporation
// Copyright (c) 2018-2019 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
......@@ -27,10 +27,9 @@
static int
pki_add_intermediate_cert(size_t device, int credid, const unsigned char *cert,
size_t cert_size, oc_sec_credusage_t credusage)
size_t cert_size)
{
OC_DBG("attempting to add an intermediate certificate");
OC_DBG("attempting to add an intermediate CA certificate");
int ret = 0;
oc_sec_creds_t *creds = oc_sec_get_creds(device);
oc_sec_cred_t *c = oc_list_head(creds->creds);
......@@ -43,89 +42,84 @@ pki_add_intermediate_cert(size_t device, int credid, const unsigned char *cert,
}
/* Parse the to-be-added intermediate cert */
unsigned char cert_copy[4096];
memcpy(cert_copy, cert, cert_size);
mbedtls_x509_crt int_ca;
mbedtls_x509_crt_init(&int_ca);
const char *pem_begin = "-----BEGIN ";
if (cert_size > strlen(pem_begin) &&
memcmp(cert, pem_begin, strlen(pem_begin)) == 0) {
cert_size = strlen((const char *)cert) + 1;
if (oc_certs_is_PEM((const unsigned char *)cert, cert_size) == 0) {
cert_copy[cert_size] = '\0';
cert_size += 1;
}
ret = mbedtls_x509_crt_parse(&int_ca, (const unsigned char *)cert, cert_size);
ret = mbedtls_x509_crt_parse(&int_ca, (const unsigned char *)cert_copy,
cert_size);
if (ret < 0) {
OC_ERR("could not parse intermediate cert");
return -1;
}
OC_DBG("parsed intermediate CA cert");
while (c) {
mbedtls_x509_crt id_cert_chain, *id_cert;
mbedtls_x509_crt_init(&id_cert_chain);
mbedtls_x509_crt id_cert_chain, *id_cert;
mbedtls_x509_crt_init(&id_cert_chain);
/* Parse the identity cert chain */
ret = mbedtls_x509_crt_parse(
&id_cert_chain, (const unsigned char *)oc_string(c->publicdata.data),
oc_string_len(c->publicdata.data) + 1);
if (ret < 0) {
OC_ERR("could not parse existing identity cert that chains to this "
"intermediate cert");
mbedtls_x509_crt_free(&int_ca);
return -1;
}
id_cert = &id_cert_chain;
for (; id_cert != NULL; id_cert = id_cert->next) {
/* If this intermediate cert is already on the chain, return */
if (id_cert->raw.len == int_ca.raw.len &&
memcmp(id_cert->raw.p, int_ca.raw.p, int_ca.raw.len) == 0) {
mbedtls_x509_crt_free(&id_cert_chain);
mbedtls_x509_crt_free(&int_ca);
OC_DBG("found intermediate cert in cred with credid %d", credid);
return 0;
}
/* Parse the identity cert chain */
ret = mbedtls_x509_crt_parse(
&id_cert_chain, (const unsigned char *)oc_string(c->publicdata.data),
oc_string_len(c->publicdata.data) + 1);
if (ret < 0) {
OC_ERR("could not parse existing identity cert that chains to this "
"intermediate cert");
mbedtls_x509_crt_free(&int_ca);
return -1;
}
OC_DBG("parsed identity cert chain");
/* break with the last cert in the identity cert chain */
if (!id_cert->next) {
break;
}
id_cert = &id_cert_chain;
for (; id_cert != NULL; id_cert = id_cert->next) {
/* If this intermediate cert is already on the chain, return */
if (id_cert->raw.len == int_ca.raw.len &&
memcmp(id_cert->raw.p, int_ca.raw.p, int_ca.raw.len) == 0) {
mbedtls_x509_crt_free(&id_cert_chain);
mbedtls_x509_crt_free(&int_ca);
OC_DBG("found intermediate cert in cred with credid %d", credid);
return 0;
}
/* Confirm that the intermediate cert is the issuer of the last cert
* in the chain, if not return.
*/
if (c->chain == NULL &&
oc_certs_is_subject_the_issuer(&int_ca, id_cert) == 0) {
mbedtls_x509_crt_free(&id_cert_chain);
/* break with the last cert in the identity cert chain */
if (!id_cert->next) {
break;
}
mbedtls_x509_crt_free(&id_cert_chain);
c = c->chain;
}
if (!c) {
mbedtls_x509_crt_free(&int_ca);
OC_ERR(
"intermediate cert not issuer of last cert in the identity cert chain");
return -1;
}
OC_DBG("adding a new intermediate cert to /oic/sec/cred");
/* Add intermediate cert to the end of the identity cert chain */
char subjectuuid[37];
oc_uuid_to_str(&c->subjectuuid, subjectuuid, 37);
int new_credid = oc_sec_add_new_cred(
device, false, NULL, -1, OC_CREDTYPE_CERT, credusage, subjectuuid, 0, 0,
NULL, OC_ENCODING_DER, int_ca.raw.len, int_ca.raw.p, NULL, NULL);
/* Confirm that the intermediate cert is the issuer of the last cert
* in the chain, if not return.
*/
if (oc_certs_is_subject_the_issuer(&int_ca, id_cert) == 0) {
id_cert->next = &int_ca;
char chain[4096];
ret = oc_certs_serialize_chain_to_pem(&id_cert_chain, chain, 4096);
if (ret > 0) {
OC_DBG("adding a new intermediate CA cert to /oic/sec/cred");
oc_free_string(&c->publicdata.data);
oc_new_string(&c->publicdata.data, chain, ret);
oc_sec_dump_cred(device);
}
if (new_credid != -1) {
oc_sec_dump_cred(device);
id_cert->next = NULL;
} else {
OC_ERR("supplied intermediate CA cert is not issuer of identity cert");
}
mbedtls_x509_crt_free(&int_ca);
mbedtls_x509_crt_free(&id_cert_chain);
return credid;
if (ret > 0) {
OC_DBG("added intermediate CA cert to /oic/sec/cred");
oc_tls_refresh_identity_certs();
return credid;
}
OC_ERR("could not add intermediate CA cert to /oic/sec/cred");
return -1;
}
static int
......@@ -137,24 +131,28 @@ pki_add_identity_cert(size_t device, const unsigned char *cert,
mbedtls_pk_context pkey;
mbedtls_pk_init(&pkey);
const char *pem_begin = "-----BEGIN ";
if (cert_size > strlen(pem_begin) &&
memcmp(cert, pem_begin, strlen(pem_begin)) == 0) {
cert_size = strlen((const char *)cert) + 1;
unsigned char cert_copy[4096];
unsigned char key_copy[4096];
memcpy(cert_copy, cert, cert_size);
memcpy(key_copy, key, key_size);
if (oc_certs_is_PEM(cert, cert_size) == 0) {
cert_copy[cert_size] = '\0';
cert_size += 1;
}
if (key_size > strlen(pem_begin) &&
memcmp(key, pem_begin, strlen(pem_begin)) == 0) {
key_size = strlen((const char *)key) + 1;
if (oc_certs_is_PEM(key, key_size) == 0) {
key_copy[key_size] = '\0';
key_size += 1;
}
/* Parse identity cert's private key */
int ret =
mbedtls_pk_parse_key(&pkey, (const unsigned char *)key, key_size, NULL, 0);
int ret = mbedtls_pk_parse_key(&pkey, (const unsigned char *)key_copy,
key_size, NULL, 0);
if (ret != 0) {
OC_ERR("could not parse identity cert's private key");
return -1;
}
OC_DBG("parsed the provided identity cert's private key");
/* Serialize identity cert's private key to DER */
uint8_t privkbuf[200];
......@@ -173,17 +171,19 @@ pki_add_identity_cert(size_t device, const unsigned char *cert,
mbedtls_x509_crt_init(&cert1);
/* Parse identity cert chain */
ret = mbedtls_x509_crt_parse(&cert1, (const unsigned char *)cert, cert_size);
ret =
mbedtls_x509_crt_parse(&cert1, (const unsigned char *)cert_copy, cert_size);
if (ret < 0) {
OC_ERR("could not parse the provided identity cert");
return -1;
}
OC_DBG("parsed the provided identity cert");
/* Extract subjectUUID from the CN property in the identity certificate */
oc_string_t subjectuuid;
if (oc_certs_parse_CN_for_UUID(&cert1, &subjectuuid) < 0) {
OC_ERR("could not extract a subjectUUID from the CN property.. Using "
OC_DBG("could not extract a subjectUUID from the CN property.. Using "
"'*'instead..");
oc_new_string(&subjectuuid, "*", 1);
}
......@@ -219,18 +219,29 @@ pki_add_identity_cert(size_t device, const unsigned char *cert,
OC_DBG("adding a new identity cert chain to /oic/sec/cred");
int credid = oc_sec_add_new_cred(
device, false, NULL, -1, OC_CREDTYPE_CERT, credusage,
oc_string(subjectuuid), OC_ENCODING_RAW, private_key_size,
privkbuf + (200 - private_key_size), OC_ENCODING_DER, cert1.raw.len,
cert1.raw.p, NULL, NULL);
char chain[4096];
ret = oc_certs_serialize_chain_to_pem(&cert1, chain, 4096);
if (credid != -1) {
oc_sec_dump_cred(device);
mbedtls_x509_crt_free(&cert1);
int credid = -1;
if (ret > 0) {
credid = oc_sec_add_new_cred(
device, false, NULL, -1, OC_CREDTYPE_CERT, credusage,
oc_string(subjectuuid), OC_ENCODING_RAW, private_key_size,
privkbuf + (200 - private_key_size), OC_ENCODING_PEM, ret,
(const uint8_t *)chain, NULL, NULL);
if (credid != -1) {
OC_DBG("added new identity cert chain to /oic/sec/cred");
oc_sec_dump_cred(device);
} else {
OC_ERR("could not add identity cert chain to /oic/sec/cred");
}
}
oc_free_string(&subjectuuid);
mbedtls_x509_crt_free(&cert1);
return credid;
}
......@@ -246,8 +257,7 @@ int
oc_pki_add_mfg_intermediate_cert(size_t device, int credid,
const unsigned char *cert, size_t cert_size)
{
return pki_add_intermediate_cert(device, credid, cert, cert_size,
OC_CREDUSAGE_MFG_CERT);
return pki_add_intermediate_cert(device, credid, cert, cert_size);
}
static int
......@@ -257,20 +267,22 @@ pki_add_trust_anchor(size_t device, const unsigned char *cert, size_t cert_size,
OC_DBG("attempting to add a trust anchor");
mbedtls_x509_crt cert1, cert2;
mbedtls_x509_crt_init(&cert1);
unsigned char cert_copy[4096];
memcpy(cert_copy, cert, cert_size);
/* Parse root cert */
const char *pem_begin = "-----BEGIN ";
if (cert_size > strlen(pem_begin) &&
memcmp(cert, pem_begin, strlen(pem_begin)) == 0) {
cert_size = strlen((const char *)cert) + 1;
if (oc_certs_is_PEM((const unsigned char *)cert, cert_size) == 0) {
cert_copy[cert_size] = '\0';
cert_size += 1;
}
int ret =
mbedtls_x509_crt_parse(&cert1, (const unsigned char *)cert, cert_size);
mbedtls_x509_crt_parse(&cert1, (const unsigned char *)cert_copy, cert_size);
if (ret < 0) {
return -1;
}
OC_DBG("parsed the provided trust anchor");
/* Pass through all known trust anchors looking for a match */
oc_sec_creds_t *creds = oc_sec_get_creds(device);
......@@ -305,18 +317,24 @@ pki_add_trust_anchor(size_t device, const unsigned char *cert, size_t cert_size,
}
}
OC_DBG("adding a new trust anchor to /oic/sec/cred");
int credid = oc_sec_add_new_cred(device, false, NULL, -1, OC_CREDTYPE_CERT,
credusage, "*", 0, 0, NULL, OC_ENCODING_DER,
cert1.raw.len, cert1.raw.p, NULL, NULL);
if (credid != -1) {
oc_sec_dump_cred(device);
OC_DBG("adding a new trust anchor entry to /oic/sec/cred");
char chain[4096];
ret = oc_certs_serialize_chain_to_pem(&cert1, chain, 4096);
if (ret > 0) {
ret = oc_sec_add_new_cred(device, false, NULL, -1, OC_CREDTYPE_CERT,
credusage, "*", 0, 0, NULL, OC_ENCODING_PEM, ret,
(const uint8_t *)chain, NULL, NULL);
if (ret != -1) {
OC_DBG("added new trust anchor entry to /oic/sec/cred");
oc_sec_dump_cred(device);
} else {
OC_ERR("could not add trust anchor entry to /oic/sec/cred");
}
}
mbedtls_x509_crt_free(&cert1);
return credid;
return ret;
}
int
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment