ParseChain update
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / adapter_util / ca_adapter_net_ssl.c
index 5c359ac..37a9d15 100644 (file)
@@ -599,27 +599,23 @@ 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]  buf     buffer with X.509 certificates. Certificates may be in either in PEM
-                       or DER format in a jumble. Each PEM certificate must be NULL-terminated.
+ * @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]  bufLen  buffer length
+ * @param[in]  errNum  number certificates that failed to parse
  *
- * @return  0 on success, -1 on error
+ * @return  number of successfully parsed certificates or -1 on error
  */
-static int ParseChain(mbedtls_x509_crt * crt, const unsigned char * buf, size_t bufLen)
+static int ParseChain(mbedtls_x509_crt * crt, unsigned char * buf, int bufLen, int * errNum)
 {
     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);
 
-    size_t pos = 0;
-    size_t len = 0;
-    unsigned char * tmp = NULL;
-    /* byte encoded ASCII string '-----BEGIN CERTIFICATE-----' */
     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
     };
-    // byte encoded ASCII string '-----END CERTIFICATE-----' */
     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
@@ -627,6 +623,13 @@ static int ParseChain(mbedtls_x509_crt * crt, const unsigned char * buf, size_t
     size_t pemCertHeaderLen = sizeof(pemCertHeader);
     size_t pemCertFooterLen = sizeof(pemCertFooter);
 
+    size_t len = 0;
+    unsigned char * tmp = NULL;
+    int count = 0;
+    int ret = 0;
+    int pos = 0;
+
+    *errNum = 0;
     while (pos < bufLen)
     {
         if (buf[pos] == 0x30 && buf[pos + 1] == 0x82)
@@ -635,11 +638,21 @@ static int ParseChain(mbedtls_x509_crt * crt, const unsigned char * buf, size_t
             CHECK_MBEDTLS_RET(mbedtls_asn1_get_len, &tmp, buf + bufLen, &len);
             if (pos + len < bufLen)
             {
-                CHECK_MBEDTLS_RET(mbedtls_x509_crt_parse_der, crt, buf + pos, len + 4);
+                ret = mbedtls_x509_crt_parse_der(crt, buf + pos, len + 4);
+                if (0 == ret)
+                {
+                    count++;
+                }
+                else
+                {
+                    (*errNum)++;
+                    OIC_LOG_V(ERROR, NET_SSL_TAG, "mbedtls_x509_crt_parse_der returned -0x%04x\n", -(ret));
+                }
             }
             pos += len + 4;
         }
-        else if (0 == memcmp(buf + pos, pemCertHeader, pemCertHeaderLen))
+        else if ((buf + pos + pemCertHeaderLen < buf + bufLen) &&
+                 (0 == memcmp(buf + pos, pemCertHeader, pemCertHeaderLen)))
         {
             void * endPos = NULL;
             endPos = memmem(&(buf[pos]), bufLen - pos, pemCertFooter, pemCertFooterLen);
@@ -649,36 +662,51 @@ static int ParseChain(mbedtls_x509_crt * crt, const unsigned char * buf, size_t
                 OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
                 return -1;
             }
-            if ((*((char*)endPos + pemCertFooterLen + 0) == 0x0d) &&
-                (*((char*)endPos + pemCertFooterLen + 1) == 0x0a) &&
-                (*((char*)endPos + pemCertFooterLen + 2) == 0x00))
+            len = (char*)endPos - ((char*)buf + pos) + pemCertFooterLen;
+            if (pos + len + 1 <= bufLen)
             {
-                len = (char*)endPos - ((char*)buf + pos) + pemCertFooterLen + 3;
-            }
-            else if ((*((char*)endPos + pemCertFooterLen + 0) == 0x0a) &&
-                     (*((char*)endPos + pemCertFooterLen + 1) == 0x00))
-            {
-                len = (char*)endPos - ((char*)buf + pos) + pemCertFooterLen + 2;
+                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
             {
-                OIC_LOG_V(ERROR, NET_SSL_TAG, "Incorrect PEM certificate ending");
-                OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
-                return -1;
+                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)
+                {
+                    count++;
+                }
+                else
+                {
+                    (*errNum)++;
+                    OIC_LOG_V(ERROR, NET_SSL_TAG, "mbedtls_x509_crt_parse returned -0x%04x\n", -(ret));
+                }
+                OICFree(lastCert);
             }
-            CHECK_MBEDTLS_RET(mbedtls_x509_crt_parse, crt, buf + pos, len);
             pos += len;
         }
         else
         {
-             OIC_LOG_BUFFER(DEBUG, NET_SSL_TAG, buf, bufLen);
-             OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
-             return -1;
+            pos++;
         }
     }
+    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 0;
-    // exit label required for CHECK_MBEDTLS_RET macro
+    return count;
+
 exit:
     return -1;
 }
@@ -707,12 +735,19 @@ static int InitPKIX(CATransportAdapter_t adapter)
                                    adapter == CA_ADAPTER_GATT_BTLE ?
                                    &g_caSslContext->clientDtlsConf : &g_caSslContext->clientTlsConf);
     // optional
-    int ret = ParseChain(&g_caSslContext->crt, g_pkiInfo.crt.data, g_pkiInfo.crt.len);
-    if (0 != ret)
+    int ret;
+    int 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");
         goto required;
     }
+    if (0 != errNum)
+    {
+        OIC_LOG_V(WARNING, NET_SSL_TAG, "Own certificate chain parsing error: %d certs failed to parse", errNum);
+        goto required;
+    }
     ret =  mbedtls_pk_parse_key(&g_caSslContext->pkey, g_pkiInfo.key.data, g_pkiInfo.key.len,
                                                                                NULL, 0);
     if (0 != ret)
@@ -735,13 +770,17 @@ static int InitPKIX(CATransportAdapter_t adapter)
     }
 
     required:
-    ret = ParseChain(&g_caSslContext->ca, g_pkiInfo.ca.data, g_pkiInfo.ca.len);
-    if(0 != ret)
+    count = ParseChain(&g_caSslContext->ca, g_pkiInfo.ca.data, g_pkiInfo.ca.len, &errNum);
+    if(0 >= count)
     {
         OIC_LOG(ERROR, NET_SSL_TAG, "CA chain parsing error");
         OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
         return -1;
     }
+    if(0 != errNum)
+    {
+        OIC_LOG_V(WARNING, NET_SSL_TAG, "CA chain parsing warning: %d certs failed to parse", errNum);
+    }
 
     ret = mbedtls_x509_crl_parse_der(&g_caSslContext->crl, g_pkiInfo.crl.data, g_pkiInfo.crl.len);
     if(0 != ret)