Commit 24b33590 authored by Kevin Kane's avatar Kevin Kane Committed by Greg Zaverucha

[IOT-1475] Remove DER/PEM mixing in ParseChain

Change cred resource to always provide own certificate as a PEM
string, and no longer require ParseChain to heuristically parse
a mixed bag of DER and PEM certs.

Also, go back to having ParseChain return an int rather than a size_t
which was changed during /W4 warning cleanup; it must be able to return
negative values to indicate errors.

Change-Id: Id36962ed580eb3bccc110aac0350349b05674ee7
Signed-off-by: default avatarKevin Kane <kkane@microsoft.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/17835Tested-by: default avatarjenkins-iotivity <jenkins@iotivity.org>
Reviewed-by: default avatarAlex Kelley <alexke@microsoft.com>
Reviewed-by: default avatarGreg Zaverucha <gregz@microsoft.com>
parent db6ac717
......@@ -114,14 +114,10 @@ typedef void (*CAgetCredentialTypesHandler)(bool * list);
*/
typedef struct
{
// own certificate chain
ByteArray_t crt;
// own public key
ByteArray_t key;
// trusted CA's
ByteArray_t ca;
// trusted CRL's
ByteArray_t crl;
ByteArray_t crt; /**< own certificate chain as a null-terminated PEM string of certificates */
ByteArray_t key; /**< own private key as binary-encoded DER */
ByteArray_t ca; /**< trusted CAs as a null-terminated PEM string of certificates */
ByteArray_t crl; /**< trusted CRLs as binary-encoded DER */
} PkiInfo_t;
/**
......
......@@ -562,116 +562,51 @@ static int RecvCallBack(void * tep, unsigned char * data, size_t dataLen)
* Parse chain of X.509 certificates.
*
* @param[out] crt container for X.509 certificates
* @param[in] data buffer with X.509 certificates. Certificates may be in either in PEM
or DER format in a jumble, delimiting symbols does not matter.
* @param[in] buf buffer with X.509 certificates. Certificates must be in a single null-terminated
* string, with each certificate in PEM encoding with headers.
* @param[in] bufLen buffer length
* @param[in] errNum number certificates that failed to parse
*
* @return number of successfully parsed certificates or -1 on error
*/
static size_t ParseChain(mbedtls_x509_crt * crt, unsigned char * buf, size_t bufLen, int * errNum)
static int ParseChain(mbedtls_x509_crt * crt, unsigned char * buf, size_t bufLen, int * errNum)
{
int ret;
OIC_LOG_V(DEBUG, NET_SSL_TAG, "In %s", __func__);
VERIFY_NON_NULL_RET(crt, NET_SSL_TAG, "Param crt is NULL" , -1);
VERIFY_NON_NULL_RET(buf, NET_SSL_TAG, "Param buf is NULL" , -1);
char pemCertHeader[] = {
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52,
0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d
};
char pemCertFooter[] = {
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49,
0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d
};
size_t pemCertHeaderLen = sizeof(pemCertHeader);
size_t pemCertFooterLen = sizeof(pemCertFooter);
size_t len = 0;
unsigned char * tmp = NULL;
size_t count = 0;
int ret = 0;
size_t pos = 0;
*errNum = 0;
while (pos < bufLen)
{
if (buf[pos] == 0x30 && buf[pos + 1] == 0x82)
{
tmp = (unsigned char *)buf + pos + 1;
CHECK_MBEDTLS_RET(mbedtls_asn1_get_len, &tmp, buf + bufLen, &len);
if (pos + len < bufLen)
{
ret = mbedtls_x509_crt_parse_der(crt, buf + pos, len + 4);
if (0 == ret)
{
count++;
}
else
if (NULL != errNum)
{
(*errNum)++;
OIC_LOG_V(ERROR, NET_SSL_TAG, "mbedtls_x509_crt_parse_der returned -0x%04x\n", -(ret));
}
}
pos += len + 4;
*errNum = 0;
}
else if ((buf + pos + pemCertHeaderLen < buf + bufLen) &&
(0 == memcmp(buf + pos, pemCertHeader, pemCertHeaderLen)))
{
void * endPos = NULL;
endPos = memmem(&(buf[pos]), bufLen - pos, pemCertFooter, pemCertFooterLen);
if (NULL == endPos)
if ((bufLen >= 2) && (buf[0] == 0x30) && (buf[1] == 0x82))
{
OIC_LOG(ERROR, NET_SSL_TAG, "Error: end of PEM certificate not found.");
OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
OIC_LOG_V(ERROR, NET_SSL_TAG, "DER-encoded certificate passed to ParseChain");
return -1;
}
len = (char*)endPos - ((char*)buf + pos) + pemCertFooterLen;
if (pos + len + 1 <= bufLen)
{
char con = buf[pos + len];
buf[pos + len] = 0x00;
ret = mbedtls_x509_crt_parse(crt, buf + pos, len + 1);
if (0 == ret)
{
count++;
}
else
{
(*errNum)++;
OIC_LOG_V(ERROR, NET_SSL_TAG, "mbedtls_x509_crt_parse returned -0x%04x\n", -(ret));
}
buf[pos + len] = con;
}
else
{
unsigned char * lastCert = (unsigned char *)OICMalloc((len + 1) * sizeof(unsigned char));
memcpy(lastCert, buf + pos, len);
lastCert[len] = 0x00;
ret = mbedtls_x509_crt_parse(crt, lastCert, len + 1);
if (0 == ret)
ret = mbedtls_x509_crt_parse(crt, buf, bufLen);
if (0 > ret)
{
count++;
OIC_LOG_V(ERROR, NET_SSL_TAG, "mbedtls_x509_crt_parse failed: -0x%04x", -(ret));
return -1;
}
else
if (NULL != errNum)
{
(*errNum)++;
OIC_LOG_V(ERROR, NET_SSL_TAG, "mbedtls_x509_crt_parse returned -0x%04x\n", -(ret));
*errNum = ret;
}
OICFree(lastCert);
}
pos += len;
}
else
ret = 0;
for (const mbedtls_x509_crt *cur = crt; cur != NULL; cur = cur->next)
{
pos++;
}
ret++;
}
OIC_LOG_V(DEBUG, NET_SSL_TAG, "%s successfully parsed %d certificates", __func__, count);
OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
return count;
exit:
return -1;
OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
return ret;
}
//Loads PKIX related information from SRM
......@@ -706,7 +641,7 @@ static int InitPKIX(CATransportAdapter_t adapter)
// optional
int ret;
int errNum;
size_t count = ParseChain(&g_caSslContext->crt, g_pkiInfo.crt.data, g_pkiInfo.crt.len, &errNum);
int count = ParseChain(&g_caSslContext->crt, g_pkiInfo.crt.data, g_pkiInfo.crt.len, &errNum);
if (0 >= count)
{
OIC_LOG(WARNING, NET_SSL_TAG, "Own certificate chain parsing error");
......
......@@ -218,20 +218,13 @@ OCStackResult GetCredRownerId(OicUuid_t *rowneruuid);
* @param[in] usage credential usage string.
*/
OCStackResult GetPemCaCert(ByteArray_t * crt, const char * usage);
/**
* Used by mbedTLS to retrieve trusted CA certificates as DER
*
* @param[out] crt certificates to be filled.
* @param[in] usage credential usage string.
*/
void GetDerCaCert(ByteArray_t * crt, const char * usage);
/**
* Used by mbedTLS to retrieve own certificate chain
*
* @param[out] crt certificate chain to be filled.
* @param[in] usage credential usage string.
*/
void GetDerOwnCert(ByteArray_t * crt, const char * usage);
void GetPemOwnCert(ByteArray_t * crt, const char * usage);
/**
* Used by mbedTLS to retrieve owm private key
*
......
......@@ -65,9 +65,9 @@
#if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
#include <mbedtls/ssl_ciphersuites.h>
#include "mbedtls/pk.h"
#include "mbedtls/base64.h"
#include "mbedtls/pem.h"
#include <mbedtls/pk.h>
#include <mbedtls/base64.h>
#include <mbedtls/pem.h>
#endif
#define TAG "OIC_SRM_CREDL"
......@@ -2880,7 +2880,7 @@ static int ConvertDerCertToPem(const uint8_t* der, size_t derLen, uint8_t** pem)
const char* pemHeader = "-----BEGIN CERTIFICATE-----\n";
const char* pemFooter = "-----END CERTIFICATE-----\n";
/* Get the length required for output*/
/* Get the length required for output */
size_t pemLen;
int ret = mbedtls_pem_write_buffer(pemHeader,
pemFooter,
......@@ -2911,7 +2911,7 @@ static int ConvertDerCertToPem(const uint8_t* der, size_t derLen, uint8_t** pem)
&pemLen);
if (ret < 0)
{
OIC_LOG_V(ERROR, TAG, "Couldn't convert cert into PEM, failed getting required length: %d", ret);
OIC_LOG_V(ERROR, TAG, "Couldn't convert cert into PEM, failed writing PEM: %d", ret);
OICFreeAndSetToNull(pem);
return ret;
}
......@@ -3034,17 +3034,12 @@ static OCStackResult GetCaCert(ByteArray_t * crt, const char * usage, OicEncodin
return OC_STACK_OK;
}
void GetDerCaCert(ByteArray_t * crt, const char * usage)
{
(void)GetCaCert(crt, usage, OIC_ENCODING_DER);
}
OCStackResult GetPemCaCert(ByteArray_t * crt, const char * usage)
{
return GetCaCert(crt, usage, OIC_ENCODING_PEM);
}
void GetDerOwnCert(ByteArray_t * crt, const char * usage)
void GetPemOwnCert(ByteArray_t * crt, const char * usage)
{
OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
if (NULL == crt || NULL == usage)
......@@ -3060,9 +3055,90 @@ void GetDerOwnCert(ByteArray_t * crt, const char * usage)
temp->credUsage != NULL &&
0 == strcmp(temp->credUsage, usage))
{
crt->data = OICRealloc(crt->data, crt->len + temp->publicData.len);
memcpy(crt->data + crt->len, temp->publicData.data, temp->publicData.len);
crt->len += temp->publicData.len;
uint8_t *p = NULL;
int mbedRet = 0;
uint8_t *pem = NULL;
size_t pemLen = 0;
bool mustFreePem = false;
bool mustAddNull = true;
switch (temp->publicData.encoding)
{
case OIC_ENCODING_DER:
case OIC_ENCODING_RAW:
mbedRet = ConvertDerCertToPem(temp->publicData.data, temp->publicData.len, &pem);
if (0 > mbedRet)
{
OIC_LOG_V(ERROR, TAG, "Failed to ConvertDerCertToPem: %d", mbedRet);
return;
}
mustFreePem = true;
mustAddNull = false; /* mbedTLS always NULL-terminates. */
pemLen = strlen((char *)pem) + 1;
break;
case OIC_ENCODING_PEM:
case OIC_ENCODING_BASE64:
pem = temp->publicData.data;
pemLen = temp->publicData.len;
/* Make sure the buffer has a terminating NULL. If not, make sure we add one later. */
for (size_t i = pemLen - 1; i > 0; i--)
{
if ('\0' == (char)pem[i])
{
mustAddNull = false;
break;
}
}
break;
default:
OIC_LOG_V(ERROR, TAG, "Unsupported encoding %d", temp->publicData.encoding);
return;
}
p = crt->data;
crt->data = OICRealloc(crt->data, crt->len + pemLen + (mustAddNull ? 1 : 0));
if (NULL == crt->data)
{
OIC_LOG(ERROR, TAG, "No memory reallocating crt->data");
OICFree(p);
if (mustFreePem)
{
OICFree(pem);
}
return;
}
/* If we're appending, subtract one from crt->len below so we overwrite the current terminating
* NULL with the beginning of the new data.
*/
if (0 < crt->len)
{
assert(crt->data[crt->len - 1] == '\0');
memcpy(crt->data + crt->len - 1, pem, pemLen);
crt->len += pemLen - 1;
}
else
{
memcpy(crt->data, pem, pemLen);
crt->len = pemLen;
}
/* If pem doesn't contain a terminating NULL, add one. */
if (mustAddNull)
{
assert(crt->data[crt->len - 1] != '\0');
crt->data[crt->len] = '\0';
crt->len += 1;
}
if (mustFreePem)
{
OICFree(pem);
}
OIC_LOG_V(DEBUG, TAG, "%s found", usage);
}
}
......
......@@ -35,9 +35,9 @@ void GetPkixInfo(PkiInfo_t * inf)
OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
return;
}
GetDerOwnCert(&inf->crt, PRIMARY_CERT);
GetPemOwnCert(&inf->crt, PRIMARY_CERT);
GetDerKey(&inf->key, PRIMARY_CERT);
GetDerCaCert(&inf->ca, TRUST_CA);
(void)GetPemCaCert(&inf->ca, TRUST_CA);
GetDerCrl(&inf->crl);
OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
}
......@@ -51,9 +51,9 @@ void GetManufacturerPkixInfo(PkiInfo_t * inf)
OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
return;
}
GetDerOwnCert(&inf->crt, MF_PRIMARY_CERT);
GetPemOwnCert(&inf->crt, MF_PRIMARY_CERT);
GetDerKey(&inf->key, MF_PRIMARY_CERT);
GetDerCaCert(&inf->ca, MF_TRUST_CA);
(void)GetPemCaCert(&inf->ca, MF_TRUST_CA);
// CRL not provided
inf->crl.data = NULL;
inf->crl.len = 0;
......
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