|
| 1 | +/* |
| 2 | + * If not stated otherwise in this file or this component's license file the |
| 3 | + * following copyright and licenses apply: |
| 4 | + * |
| 5 | + * Copyright 2015 RDK Management |
| 6 | + * |
| 7 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
| 8 | + * you may not use this file except in compliance with the License. |
| 9 | + * You may obtain a copy of the License at |
| 10 | + * |
| 11 | + * http://www.apache.org/licenses/LICENSE-2.0 |
| 12 | + * |
| 13 | + * Unless required by applicable law or agreed to in writing, software |
| 14 | + * distributed under the License is distributed on an "AS IS" BASIS, |
| 15 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 16 | + * See the License for the specific language governing permissions and |
| 17 | + * limitations under the License. |
| 18 | +*/ |
| 19 | +#include <string.h> |
| 20 | +#include <sys/stat.h> |
| 21 | +#include <openssl/pkcs12.h> |
| 22 | +#include <openssl/pem.h> |
| 23 | +#include <openssl/evp.h> |
| 24 | +#include <errno.h> |
| 25 | +#include <dirent.h> |
| 26 | +#include "rdkcertselector.h" |
| 27 | +#include "ctrlm_auth_certificate.h" |
| 28 | +#include "ctrlm_utils.h" |
| 29 | +#include "ctrlm_log.h" |
| 30 | + |
| 31 | +#define CERT_FILENAME_PREFIX "file://" |
| 32 | + |
| 33 | +ctrlm_auth_certificate_t *ctrlm_auth_certificate_get() { |
| 34 | + return(new(ctrlm_auth_certificate_t)); |
| 35 | +} |
| 36 | + |
| 37 | +ctrlm_auth_certificate_t::ctrlm_auth_certificate_t() { |
| 38 | + |
| 39 | + this->device_cert.type = CTRLM_VOICE_CERT_TYPE_NONE; |
| 40 | + this->ocsp_verify_stapling = false; |
| 41 | + this->ocsp_verify_ca = false; |
| 42 | + |
| 43 | + char *cert_path = NULL; |
| 44 | + char *cert_password = NULL; |
| 45 | + rdkcertselector_h cert_selector = rdkcertselector_new( NULL, NULL, "MTLS" ); |
| 46 | + |
| 47 | + if(cert_selector == NULL){ |
| 48 | + XLOGD_TELEMETRY("cert selector init failed"); |
| 49 | + } else { |
| 50 | + rdkcertselectorStatus_t cert_status = rdkcertselector_getCert(cert_selector, &cert_path, &cert_password); |
| 51 | + |
| 52 | + if(cert_status != certselectorOk) { |
| 53 | + XLOGD_TELEMETRY("cert selector retrieval failed"); |
| 54 | + } else { |
| 55 | + if(cert_path == NULL || cert_password == NULL) { |
| 56 | + XLOGD_TELEMETRY("cert selector get failed"); |
| 57 | + } else { |
| 58 | + |
| 59 | + char *local_path = cert_path; |
| 60 | + if(strncmp(local_path, CERT_FILENAME_PREFIX, strlen(CERT_FILENAME_PREFIX)) == 0) { |
| 61 | + local_path += strlen(CERT_FILENAME_PREFIX); |
| 62 | + } |
| 63 | + if(!this->device_cert_p12_set(local_path, cert_password)) { |
| 64 | + XLOGD_TELEMETRY("unable to set device certificate <%s>", local_path); |
| 65 | + } else { |
| 66 | + struct stat file_info; |
| 67 | + // OCSP is a global setting that is enabled via RFC in systemd service ocsp-support |
| 68 | + if(stat("/tmp/.EnableOCSPStapling", &file_info) == 0) { |
| 69 | + XLOGD_TELEMETRY("OCSP verification enabled (stapling)"); |
| 70 | + this->ocsp_verify_stapling = true; |
| 71 | + } |
| 72 | + if(stat("/tmp/.EnableOCSPCA", &file_info) == 0) { |
| 73 | + XLOGD_TELEMETRY("OCSP verification enabled (CA)"); |
| 74 | + this->ocsp_verify_ca = true; |
| 75 | + } |
| 76 | + if(!this->ocsp_verify_stapling && !this->ocsp_verify_ca) { |
| 77 | + XLOGD_TELEMETRY("OCSP verification disabled"); |
| 78 | + } |
| 79 | + } |
| 80 | + } |
| 81 | + } |
| 82 | + } |
| 83 | + |
| 84 | + if(cert_selector != NULL) { |
| 85 | + rdkcertselector_free(&cert_selector); |
| 86 | + } |
| 87 | +} |
| 88 | + |
| 89 | +ctrlm_auth_certificate_t::~ctrlm_auth_certificate_t() { |
| 90 | + if(this->device_cert.type == CTRLM_VOICE_CERT_TYPE_P12) { |
| 91 | + if(this->device_cert.cert.p12.certificate != NULL) { |
| 92 | + free((void *)this->device_cert.cert.p12.certificate); |
| 93 | + } |
| 94 | + if(this->device_cert.cert.p12.passphrase != NULL) { |
| 95 | + free((void *)this->device_cert.cert.p12.passphrase); |
| 96 | + } |
| 97 | + } |
| 98 | +} |
| 99 | + |
| 100 | +bool ctrlm_auth_certificate_t::device_cert_get(ctrlm_voice_cert_t &device_cert, bool &ocsp_verify_stapling, bool &ocsp_verify_ca) { |
| 101 | + |
| 102 | + device_cert = this->device_cert; |
| 103 | + ocsp_verify_stapling = this->ocsp_verify_stapling; |
| 104 | + ocsp_verify_ca = this->ocsp_verify_ca; |
| 105 | + return(true); |
| 106 | +} |
| 107 | + |
| 108 | +bool ctrlm_auth_certificate_t::device_cert_p12_set(const char *certificate, const char *passphrase) { |
| 109 | + bool cert_valid = false; |
| 110 | + |
| 111 | + // Extract the certificate, private key and additional certificates |
| 112 | + PKCS12 *p12_cert = NULL; |
| 113 | + EVP_PKEY *pkey = NULL; |
| 114 | + X509 *x509_cert = NULL; |
| 115 | + STACK_OF(X509) *additional_certs = NULL; |
| 116 | + |
| 117 | + do { |
| 118 | + FILE *fp = fopen(certificate, "rb"); |
| 119 | + if(fp == NULL) { |
| 120 | + XLOGD_ERROR("unable to open P12 certificate <%s>", certificate); |
| 121 | + break; |
| 122 | + } |
| 123 | + |
| 124 | + d2i_PKCS12_fp(fp, &p12_cert); |
| 125 | + fclose(fp); |
| 126 | + fp = NULL; |
| 127 | + |
| 128 | + if(p12_cert == NULL) { |
| 129 | + XLOGD_ERROR("unable to read P12 certificate <%s>", certificate); |
| 130 | + break; |
| 131 | + } |
| 132 | + |
| 133 | + if(1 != PKCS12_parse(p12_cert, passphrase, &pkey, &x509_cert, &additional_certs)) { |
| 134 | + XLOGD_ERROR("unable to parse P12 certificate <%s>", certificate); |
| 135 | + break; |
| 136 | + } |
| 137 | + |
| 138 | + this->device_cert.type = CTRLM_VOICE_CERT_TYPE_P12; |
| 139 | + this->device_cert.cert.p12.certificate = strdup(certificate); |
| 140 | + this->device_cert.cert.p12.passphrase = strdup(passphrase); |
| 141 | + |
| 142 | + // Ensure the strings were duplicated |
| 143 | + if(this->device_cert.cert.p12.certificate == NULL || this->device_cert.cert.p12.passphrase == NULL) { |
| 144 | + this->device_cert.type = CTRLM_VOICE_CERT_TYPE_NONE; |
| 145 | + if(this->device_cert.cert.p12.certificate != NULL) { |
| 146 | + free((void *)this->device_cert.cert.p12.certificate); |
| 147 | + } |
| 148 | + if(this->device_cert.cert.p12.passphrase != NULL) { |
| 149 | + free((void *)this->device_cert.cert.p12.passphrase); |
| 150 | + } |
| 151 | + } else { |
| 152 | + cert_valid = true; |
| 153 | + } |
| 154 | + |
| 155 | + } while(0); |
| 156 | + |
| 157 | + if(p12_cert != NULL) { |
| 158 | + PKCS12_free(p12_cert); |
| 159 | + } |
| 160 | + if(pkey != NULL) { |
| 161 | + EVP_PKEY_free(pkey); |
| 162 | + } |
| 163 | + if(x509_cert != NULL) { |
| 164 | + X509_free(x509_cert); |
| 165 | + } |
| 166 | + if(additional_certs != NULL) { |
| 167 | + sk_X509_pop_free(additional_certs, X509_free); |
| 168 | + } |
| 169 | + |
| 170 | + return(cert_valid); |
| 171 | +} |
0 commit comments