--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 - 2025 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include <openssl/pem.h>
+#include "cert_utils.h"
+#include "log.h"
+#include "device_certificate_manager.h"
+
+
+void parse_cert_chain(STACK_OF(X509) * chain_store, const char * buffer, size_t length, bool is_pem)
+{
+ X509 *cert = nullptr;
+ BIO_ptr bio(BIO_new_mem_buf(buffer, length), ::BIO_free);
+ while(true) {
+ if(is_pem) {
+ cert = PEM_read_bio_X509(bio.get(), NULL, NULL, NULL);
+ } else {
+ cert = d2i_X509_bio(bio.get(), NULL);
+ }
+
+ if (cert != nullptr) {
+ sk_X509_push(chain_store, cert);
+ } else {
+ break;
+ }
+ }
+}
+
+int x509_rewriter::parse(const char * buffer, size_t length)
+{
+ BIO_ptr bio(BIO_new_mem_buf(buffer, length), ::BIO_free);
+
+ parse_cert_chain(fChain, buffer, length, true); // Parse PEM type cert chain
+ if (sk_X509_num(fChain) == 0) { // Try for DER type cert chain
+ LOGW("No PEM Certificates in Cert Chain. So tring to parse DER certificates");
+ parse_cert_chain(fChain, buffer, length, false);
+ }
+
+ if (sk_X509_num(fChain) == 0) {
+ LOGE("No Certificates in Cert Chain. buffer length=" << length);
+ return DCM_ERROR_NO_DATA;
+ }
+
+ return DCM_ERROR_NONE;
+}
+
+std::string x509_rewriter::emit_pem()
+{
+ BIO_ptr bio(BIO_new(BIO_s_mem()), ::BIO_free);
+
+ if (sk_X509_num(fChain) == 0)
+ return std::string();
+
+ for (int i = 0; i < sk_X509_num(fChain); i++) {
+ X509_ptr cert(sk_X509_value(fChain, i), ::X509_free);
+ if (!PEM_write_bio_X509(bio.get(), cert.get())) {
+ // Error. Returns an empty string.
+ return std::string();
+ }
+ }
+
+ BUF_MEM *mem = nullptr;
+ BIO_get_mem_ptr(bio.get(), &mem);
+ if (mem)
+ return std::string(mem->data, mem->length);
+ else
+ return std::string();
+}
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#ifndef DCM_DAEMON_CERT_UTILS_H_
+#define DCM_DAEMON_CERT_UTILS_H_
+
+#include <openssl/x509.h>
+#include <string>
+#include <memory>
+
+
+using BIO_ptr = std::unique_ptr<BIO, decltype(&::BIO_free)>;
+using X509_ptr = std::unique_ptr<X509, decltype(&::X509_free)>;
+
+struct x509_rewriter {
+private:
+ STACK_OF(X509) * fChain;
+ size_t fChainSize = 0;
+ size_t fNumCerts = 0;
+
+public:
+ x509_rewriter() :
+ fChain(sk_X509_new_null()) {
+ }
+
+ ~x509_rewriter() {
+ sk_X509_free(fChain);
+ }
+
+ int parse(const char * buffer, size_t length);
+ std::string emit_pem();
+};
+
+#endif /* DCM_DAEMON_CERT_UTILS_H_ */
\ No newline at end of file
#include "dcm_server.h"
#include "device_certificate_manager_ext_types.h"
#include "device_certificate_manager.h"
+#include "cert_utils.h"
#include "log.h"
#include <hal/hal-security-certs.h>
return;
}
- if (cert_chain->buffer != NULL && cert_chain->length >= sPEMHeader.length() &&
- !memcmp(sPEMHeader.c_str(), cert_chain->buffer, sPEMHeader.size()) &&
- cert_chain->buffer[cert_chain->length - 1] != '\0')
- {
- // Add missing 0
- char* new_buffer = static_cast<char*>(realloc(cert_chain->buffer, cert_chain->length + 1));
- if (new_buffer == NULL) {
- reply_error(msg, certificateResponse, backend_to_dcm_error(-ENOMEM),
- "Failed reallocating memory for certificate chain");
- return;
- }
-
- cert_chain->buffer = new_buffer;
- cert_chain->length = cert_chain->length + 1;
- strncat(cert_chain->buffer, "\0", 1);
- }
+ x509_rewriter parser;
+ error = parser.parse(cert_chain->buffer, cert_chain->length);
+ if (error != DCM_ERROR_NONE) {
+ reply_error(msg, certificateResponse, error, "Failed to parse certificate chain");
+ return;
+ }
- *certificateResponse->mutable_cert_chain() = std::string(cert_chain->buffer, cert_chain->length);
+ *certificateResponse->mutable_cert_chain() = parser.emit_pem();
certificateResponse->set_result(0);
reply(msg);
} catch (std::bad_alloc&) {
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 - 2021 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the \n"License\n");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an \n"AS IS\n" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include <iostream>
+#include <string>
+#include <openssl/pem.h>
+
+
+#include "cert_utils.h"
+#include "device_certificate_manager.h"
+
+#include "test_macros.h"
+
+namespace {
+
+ const std::string cert_leaf =
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIIDezCCAmMCCQCsmy9mf2NyaTANBgkqhkiG9w0BAQsFADBWMRowGAYDVQQKDBFU\n"
+ "aXplbiBBc3NvY2lhdGlvbjEaMBgGA1UECwwRVGl6ZW4gQXNzb2NpYXRpb24xHDAa\n"
+ "BgNVBAMME1RpemVuIERldmVsb3BlcnMgQ0EwHhcNMTgxMTI4MDY1MTIyWhcNMjYx\n"
+ "MjI1MDY1MTIyWjCBqDELMAkGA1UEBhMCS08xETAPBgNVBAgMCEt5ZW9uZ2tpMQ4w\n"
+ "DAYDVQQHDAVTdXdvbjEuMCwGA1UECgwlU2Ftc3VuZyBFbGVjdHJvbmljcyBEaWdp\n"
+ "dGFsIEFwcGxpYW5jZTERMA8GA1UECwwIU2VjdXJpdHkxEDAOBgNVBAMMB2Jyby5r\n"
+ "aW0xITAfBgkqhkiG9w0BCQEWEnNkbC5kYUBzYW1zdW5nLmNvbTCCASIwDQYJKoZI\n"
+ "hvcNAQEBBQADggEPADCCAQoCggEBAPaIXmFsFZ/EXRUeoNyodAClCexSfTI+Y2Yr\n"
+ "MzxDlgPrv/BYeEkhxBzD/efOUWceHrzpxARWAqWk6NVUyAzXkSWbys52K6UDpVLL\n"
+ "JX1mrj9YiVVszhVV6/sajwxs1RFNPYqz5Evoxp7DuT1ryQdhud+ZvioeSL4eR6a0\n"
+ "B55SEG1172eJHKp97oU+l29q1eB7+nOlPM2zfYdd6y2O/WQ36XZG0/S8HY8dP66c\n"
+ "MovhB5Y4dAR+udQ5YLow0/Y0pmHJynFLaBhm9ySQYX1QTmSbu5uVbj/lbhriZPLX\n"
+ "3q/C/W1EkyvrsGRCVkHxT8XApdgoZO6+ld1nFpM/pH84tBxJ9bkCAwEAATANBgkq\n"
+ "hkiG9w0BAQsFAAOCAQEAPh5QN7x59G1TUTdUqJ1ZcMLLZsAACX1lphMUg0oTIM0r\n"
+ "ISdEBBuMLExkGwY5I8RqZ8rYeOESft2SbrIRf4Y830LaV99tJMDBCfzmzNm5UWpO\n"
+ "Fb2cT//N9VvLuc2Kigr+X5/RlAkWRnYUc4D+ZE1nXEc0VoSNUDzeqO8c971zeg10\n"
+ "bl+gzqvrZIK4GqCeJdCTc1HO1INjNq+t1c1ViwgtAzJv4PZlXEHhWQmsoOHRSb1l\n"
+ "iGpQ59qYv8lqmXLa+FgzlQPH+AdCIP9YSOoYBf6tJCTA4YjNyn1PiTMH1hMwER6k\n"
+ "MwFCQbyfmgXnKxENjk94FCQ/fBb4SxEwe0u6iccA4w==\n"
+ "-----END CERTIFICATE-----\n";
+
+ const std::string cert_ca =
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIIDOTCCAiGgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMRowGAYDVQQKDBFUaXpl\n"
+ "biBBc3NvY2lhdGlvbjEaMBgGA1UECwwRVGl6ZW4gQXNzb2NpYXRpb24xHjAcBgNV\n"
+ "BAMMFVRpemVuIERldmVsb3BlcnMgUm9vdDAeFw0xMjAxMDEwMDAwMDBaFw0yNzAx\n"
+ "MDEwMDAwMDBaMFYxGjAYBgNVBAoMEVRpemVuIEFzc29jaWF0aW9uMRowGAYDVQQL\n"
+ "DBFUaXplbiBBc3NvY2lhdGlvbjEcMBoGA1UEAwwTVGl6ZW4gRGV2ZWxvcGVycyBD\n"
+ "QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANVGhRGmMIUyBA7oPCz8\n"
+ "Sxut6z6HNkF4oDIuzuKaMzRYPeWodwe9O0gmqAkToQHfwg2giRhE5GoPld0fq+OY\n"
+ "MMwSasCug8dwODx1eDeSYVuOLWRxpAmbTXOsSFi6VoWeyaPEm18JBHvZBsU5YQtg\n"
+ "Z6Kp7MqzvQg3pXOxtajjvyHxiatJl+xXrHgcXC1wgyG3buty7u/Fi2mvKXJ0PRJc\n"
+ "CjjK81dqe/Vr20sRUCrbk02zbm5ggFt/jIEhV8wbFRQpliobc7J4dSTKhFfrqGM8\n"
+ "rdd54LYhD7gSI1CFSe16pUXfcVR7FhJztRaiGLnCrwBEdyTZ248+D4L/qR/D0axb\n"
+ "3jcCAwEAAaMQMA4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAnOXX\n"
+ "Q/1O/QTDHyrmQDtFziqPY3xWlJBqJtEqXiT7Y+Ljpe66e+Ee/OjQMlZe8gu21/8c\n"
+ "KklH95RxjopMWCVedXDUbWdvS2+CdyvVW/quT2E0tjqIzXDekUTYwwhlPWlGxvfj\n"
+ "3VsxqSFq3p8Brl041Gx5RKAGyKVsMfTLhbbwSWwApuBUxYfcNpKwLWGPXkysu+Hc\n"
+ "tY03OKv4/xKBnVWiN8ex/Sgesi0M+OBAOMdZMPK32uJBTeKFx1xZgTLIhk45V0hP\n"
+ "OomPjZloiv0LSS11eyd451ufjW0iHRE7WlpR6EvIW6TFyZgMpQq+kg4hWl2SBTf3\n"
+ "s2VI8Ygz7gj8TMlClg==\n"
+ "-----END CERTIFICATE-----\n";
+
+ const std::string cert_root =
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIIDOzCCAiOgAwIBAgIBADANBgkqhkiG9w0BAQUFADBYMRowGAYDVQQKDBFUaXpl\n"
+ "biBBc3NvY2lhdGlvbjEaMBgGA1UECwwRVGl6ZW4gQXNzb2NpYXRpb24xHjAcBgNV\n"
+ "BAMMFVRpemVuIERldmVsb3BlcnMgUm9vdDAeFw0xMjAxMDEwMDAwMDBaFw0zMjAx\n"
+ "MDEwMDAwMDBaMFgxGjAYBgNVBAoMEVRpemVuIEFzc29jaWF0aW9uMRowGAYDVQQL\n"
+ "DBFUaXplbiBBc3NvY2lhdGlvbjEeMBwGA1UEAwwVVGl6ZW4gRGV2ZWxvcGVycyBS\n"
+ "b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp2rCwXTYh28vcagX\n"
+ "WLIeVtEvXA5EeTR9UnL4Dzyd7hIq8rkxLbIMMOcCrXMTc7bEH2twFaTuXxyKXMW/\n"
+ "2c+id3m3Z1B5caCqwSPr72oKPSI4jSkvrAC5W7EHx16M818aG4tQkXIUBhDrtSmH\n"
+ "6dFOdt8zGq2fanj1sETfUmXAeLGE7OQYcEb2SoWGXR75Ytfp1LAw/L3luuG/kbzB\n"
+ "crZt1Cv05jfCP575eope6p5p80Gl0tieXyPYhSLVTLwhEdWx18CMaC7IXQo2Bm+J\n"
+ "djDH0Ruh/vTRnjFtmVB+nBOZNVzMHNOPUVFKSgysX/+PlM4jBTvbaTnPCZUkC/O7\n"
+ "5tYIpwIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQBw\n"
+ "95ibcuAiKpAEqBMyTZtOf0okhSi9NYfs/AFIPLH5REnhtQkPmKsvDp21OSdzrFEL\n"
+ "42rV94K98QChD9tGO6Mwp1ZHM3No7/PLC3EelOwmn4dr3KPGdjvQNSwKRblGh0Hj\n"
+ "n4fI+studFLLv6ldCLIpA/Ssgf9GuUbcjTC8OWBYPVUQ6YoXAcuHbfhr6a2IXRTj\n"
+ "lJUCt3qWyciP2H/R+oNBSjtlq13ZT+D9AQMmIG/5w1tK0HzDRhORfWlKCo5JKn0A\n"
+ "iQq2fwtoB0JQEHRKCKZYWghG41HuKc82xLf6H7x24XWOAlXb0SpvVENT1i89XNrj\n"
+ "XS4modIY545rYjI1amfL\n"
+ "-----END CERTIFICATE-----\n";
+
+ const std::string cert_chain_in_pem = cert_leaf + cert_ca + cert_root;
+
+
+ void parse_cert(STACK_OF(X509) * chain_store, const std::string pem_cert)
+ {
+ X509 *cert = nullptr;
+ BIO_ptr bio(BIO_new_mem_buf(pem_cert.c_str(), pem_cert.size()), ::BIO_free);
+ cert = PEM_read_bio_X509(bio.get(), NULL, NULL, NULL);
+ if (cert != nullptr)
+ sk_X509_push(chain_store, cert);
+ }
+};
+
+
+
+BOOST_AUTO_TEST_SUITE(UNIT_TEST)
+
+POSITIVE_TEST_CASE(test11_cert_chain_in_pem)
+{
+ int ret = DCM_ERROR_NONE;
+
+ x509_rewriter parser;
+ ret = parser.parse(cert_chain_in_pem.c_str(), cert_chain_in_pem.size());
+ BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_NONE);
+
+ std::string emitted_cert = parser.emit_pem();
+ BOOST_REQUIRE(emitted_cert.size() > 0);
+}
+
+POSITIVE_TEST_CASE(test12_cert_chain_in_der)
+{
+ int ret = DCM_ERROR_NONE;
+
+ STACK_OF(X509) *chain_store = sk_X509_new_null();
+ parse_cert(chain_store, cert_leaf);
+ parse_cert(chain_store, cert_ca);
+ parse_cert(chain_store, cert_root);
+
+ BIO_ptr bio(BIO_new(BIO_s_mem()), ::BIO_free);
+ for (int i = 0; i < sk_X509_num(chain_store); i++) {
+ X509_ptr cert(sk_X509_value(chain_store, i), ::X509_free);
+ if (!i2d_X509_bio(bio.get(), cert.get())) {
+ // error case
+ std::cout << "Error happended during cert conversion" << std::endl;
+ }
+ }
+ sk_X509_free(chain_store);
+
+ BUF_MEM *mem = nullptr;
+ BIO_get_mem_ptr(bio.get(), &mem);
+
+ x509_rewriter parser;
+ ret = parser.parse(mem->data, mem->length);
+ BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_NONE);
+
+ std::string cert_chain_from_der = parser.emit_pem();
+ BOOST_REQUIRE(cert_chain_from_der.size() > 0);
+
+ x509_rewriter parser2;
+ ret = parser2.parse(cert_chain_in_pem.c_str(), cert_chain_in_pem.size());
+ BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_NONE);
+ std::string cert_chain_from_pem = parser2.emit_pem();
+ BOOST_REQUIRE_EQUAL(cert_chain_from_pem, cert_chain_from_der);
+}
+
+BOOST_AUTO_TEST_SUITE_END()