/* * Copyright (C) 2020 iopsys Software Solutions AB * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 2.1 * as published by the Free Software Foundation * * Author: Omar Kallel */ #include "security.h" #define DATE_LEN 128 #define MAX_CERT 32 static char certifcates_paths[MAX_CERT][256]; struct certificate_profile { char *path; #ifdef LOPENSSL X509 *openssl_cert; #elif LMBEDTLS mbedtls_x509_crt mbdtls_cert; #endif struct uci_section *dmmap_sect; }; /************************************************************ * Init function *************************************************************/ void init_certificate(char *path, #ifdef LOPENSSL X509 *cert, #elif LMBEDTLS mbedtls_x509_crt cert, #endif struct uci_section *dmsect, struct certificate_profile *certprofile) { certprofile->path = path; #ifdef LOPENSSL certprofile->openssl_cert = cert; #elif LMBEDTLS certprofile->mbdtls_cert = cert; #endif certprofile->dmmap_sect = dmsect; } #ifdef LOPENSSL static char *get_certificate_sig_alg(int sig_nid) { switch(sig_nid) { case NID_sha256WithRSAEncryption: return LN_sha256WithRSAEncryption; case NID_sha384WithRSAEncryption: return LN_sha384WithRSAEncryption; case NID_sha512WithRSAEncryption: return LN_sha512WithRSAEncryption; case NID_sha224WithRSAEncryption: return LN_sha224WithRSAEncryption; case NID_sha512_224WithRSAEncryption: return LN_sha512_224WithRSAEncryption; case NID_sha512_256WithRSAEncryption: return LN_sha512_224WithRSAEncryption; case NID_pbeWithMD2AndDES_CBC: return LN_pbeWithMD2AndDES_CBC; case NID_pbeWithMD5AndDES_CBC: return LN_pbeWithMD5AndDES_CBC; case NID_pbeWithMD2AndRC2_CBC: return LN_pbeWithMD5AndDES_CBC; case NID_pbeWithMD5AndRC2_CBC: return LN_pbeWithMD5AndRC2_CBC; case NID_pbeWithSHA1AndDES_CBC: return LN_pbeWithSHA1AndDES_CBC; case NID_pbeWithSHA1AndRC2_CBC: return LN_pbeWithSHA1AndDES_CBC; case NID_pbe_WithSHA1And128BitRC4: return LN_pbe_WithSHA1And128BitRC4; case NID_pbe_WithSHA1And40BitRC4: return LN_pbe_WithSHA1And40BitRC4; case NID_pbe_WithSHA1And3_Key_TripleDES_CBC: return LN_pbe_WithSHA1And3_Key_TripleDES_CBC; case NID_pbe_WithSHA1And2_Key_TripleDES_CBC: return LN_pbe_WithSHA1And2_Key_TripleDES_CBC; case NID_pbe_WithSHA1And128BitRC2_CBC: return LN_pbe_WithSHA1And128BitRC2_CBC; case NID_pbe_WithSHA1And40BitRC2_CBC: return LN_pbe_WithSHA1And40BitRC2_CBC; case NID_sm3WithRSAEncryption: return LN_sm3WithRSAEncryption; case NID_shaWithRSAEncryption: return LN_shaWithRSAEncryption; case NID_md2WithRSAEncryption: return LN_md2WithRSAEncryption; case NID_md4WithRSAEncryption: return LN_md4WithRSAEncryption; case NID_md5WithRSAEncryption: return LN_md5WithRSAEncryption; case NID_sha1WithRSAEncryption: return LN_sha1WithRSAEncryption; default: return ""; } } #elif LMBEDTLS static char *get_certificate_md(mbedtls_md_type_t sig_md) { switch(sig_md) { case MBEDTLS_MD_MD2: return "md2"; case MBEDTLS_MD_MD4: return "md4"; case MBEDTLS_MD_MD5: return "md5"; case MBEDTLS_MD_SHA1: return "sha1"; case MBEDTLS_MD_SHA224: return "sha224"; case MBEDTLS_MD_SHA256: return "sha256"; case MBEDTLS_MD_SHA384: return "sha384"; case MBEDTLS_MD_SHA512: return "sha512"; case MBEDTLS_MD_RIPEMD160: return "ripemd160"; default: return ""; } return ""; } static char *get_certificate_pk(mbedtls_pk_type_t sig_pk) { switch(sig_pk) { case MBEDTLS_PK_RSA: return "RSA"; case MBEDTLS_PK_ECKEY: return "ECKEY"; case MBEDTLS_PK_ECKEY_DH: return "ECKEYDH"; case MBEDTLS_PK_ECDSA: return "ECDSA"; case MBEDTLS_PK_RSA_ALT: return "RSAALT"; case MBEDTLS_PK_RSASSA_PSS: return "RSASSAPSS"; default: return ""; } return ""; } #endif /************************************************************* * ENTRY METHOD **************************************************************/ static void get_certificate_paths(void) { struct uci_section *s; int cidx; for (cidx=0; cidx= MAX_CERT) break; if(!file_exists(cert) || !is_regular_file(cert)) continue; strncpy(certifcates_paths[cidx], cert, 256); cidx++; } uci_foreach_sections("openvpn", "openvpn", s) { char *cert; dmuci_get_value_by_section_string(s, "cert", &cert); if (*cert == '\0') continue; if (cidx >= MAX_CERT) break; if(!file_exists(cert) || !is_regular_file(cert)) continue; strncpy(certifcates_paths[cidx], cert, 256); cidx++; } uci_foreach_sections("obuspa", "obuspa", s) { char *cert; dmuci_get_value_by_section_string(s, "cert", &cert); if (*cert == '\0') continue; if (cidx >= MAX_CERT) break; if(!file_exists(cert) || !is_regular_file(cert)) continue; strncpy(certifcates_paths[cidx], cert, 256); cidx++; } } static int browseSecurityCertificateInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) { #if defined(LOPENSSL) || defined(LMBEDTLS) char *inst = NULL, *max_inst = NULL; struct uci_section *dmmap_sect = NULL; struct certificate_profile certificateprofile = {}; get_certificate_paths(); int i; for (i = 0; i < MAX_CERT; i++) { if(!strlen(certifcates_paths[i])) break; #ifdef LOPENSSL FILE *fp = NULL; fp = fopen(certifcates_paths[i], "r"); if (fp == NULL) continue; X509 *cert = PEM_read_X509(fp, NULL, NULL, NULL); if (!cert) { fclose(fp); continue; } if ((dmmap_sect = get_dup_section_in_dmmap_opt("dmmap_security", "security_certificate", "path", certifcates_paths[i])) == NULL) { dmuci_add_section_bbfdm("dmmap_security", "security_certificate", &dmmap_sect); dmuci_set_value_by_section_bbfdm(dmmap_sect, "path", certifcates_paths[i]); } init_certificate(certifcates_paths[i], cert, dmmap_sect, &certificateprofile); inst = handle_update_instance(1, dmctx, &max_inst, update_instance_alias, 5, dmmap_sect, "security_certificate_instance", "security_certificate_alias", "dmmap_security", "security_certificate"); if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)&certificateprofile, inst) == DM_STOP) break; X509_free(cert); cert = NULL; fclose(fp); fp = NULL; #elif LMBEDTLS mbedtls_x509_crt cacert; mbedtls_x509_crt_init( &cacert ); int ret = mbedtls_x509_crt_parse_file( &cacert, certifcates_paths[i]); if (ret < 0) continue; if ((dmmap_sect = get_dup_section_in_dmmap_opt("dmmap_security", "security_certificate", "path", certifcates_paths[i])) == NULL) { dmuci_add_section_bbfdm("dmmap_security", "security_certificate", &dmmap_sect); dmuci_set_value_by_section_bbfdm(dmmap_sect, "path", certifcates_paths[i]); } init_certificate(certifcates_paths[i], cacert, dmmap_sect, &certificateprofile); inst = handle_update_instance(1, dmctx, &max_inst, update_instance_alias, 5, dmmap_sect, "security_certificate_instance", "security_certificate_alias", "dmmap_security", "security_certificate"); if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)&certificateprofile, inst) == DM_STOP) break; #endif } #endif return 0; } /************************************************************* * GET & SET PARAM **************************************************************/ static int get_Security_CertificateNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { int number = 0; #if defined(LOPENSSL) || defined(LMBEDTLS) get_certificate_paths(); int i; for (i=0; i < MAX_CERT; i++) { if(!strlen(certifcates_paths[i])) break; #ifdef LOPENSSL FILE *fp = NULL; fp = fopen(certifcates_paths[i], "r"); if (fp == NULL) continue; X509 *cert = PEM_read_X509(fp, NULL, NULL, NULL); if (!cert) { fclose(fp); continue; } number++; X509_free(cert); cert = NULL; fclose(fp); fp = NULL; #elif LMBEDTLS mbedtls_x509_crt cacert; mbedtls_x509_crt_init( &cacert ); int ret = mbedtls_x509_crt_parse_file( &cacert, certifcates_paths[i]); if (ret < 0) continue; number++; #endif } #endif dmasprintf(value, "%d", number); return 0; } static int get_SecurityCertificate_LastModif(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { struct certificate_profile *cert_profile = (struct certificate_profile*)data; struct stat b; char t[sizeof("AAAA-MM-JJTHH:MM:SSZ")] = "0001-01-01T00:00:00Z"; if (!stat(cert_profile->path, &b)) strftime(t, sizeof(t), "%Y-%m-%dT%H:%M:%SZ", localtime(&b.st_mtime)); *value = dmstrdup(t); return 0; } static int get_SecurityCertificate_SerialNumber(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { *value = ""; #ifdef LOPENSSL struct certificate_profile *cert_profile = (struct certificate_profile*)data; ASN1_INTEGER *serial = X509_get_serialNumber(cert_profile->openssl_cert); *value = stringToHex((char *)serial->data, serial->length); #elif LMBEDTLS struct certificate_profile *cert_profile = (struct certificate_profile*)data; *value = stringToHex(cert_profile->mbdtls_cert.serial.p, cert_profile->mbdtls_cert.serial.len); #endif return 0; } static int get_SecurityCertificate_Issuer(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { *value = ""; #ifdef LOPENSSL struct certificate_profile *cert_profile = (struct certificate_profile*)data; *value = X509_NAME_oneline(X509_get_issuer_name(cert_profile->openssl_cert), NULL, 0); if (*value[0] == '/') (*value)++; *value = replace_char(*value, '/', ' '); #elif LMBEDTLS struct certificate_profile *cert_profile = (struct certificate_profile*)data; size_t olen; unsigned char issuer[4096]; int ret2 = mbedtls_base64_encode(issuer, 4096, &olen, cert_profile->mbdtls_cert.issuer.val.p, cert_profile->mbdtls_cert.issuer.val.len ); if(ret2 != 0) return 0; *value = decode64(issuer); #endif return 0; } static int get_SecurityCertificate_NotBefore(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { *value = "0001-01-01T00:00:00Z"; #ifdef LOPENSSL struct tm not_before_time; struct certificate_profile *cert_profile = (struct certificate_profile*)data; char not_before_str[DATE_LEN]; ASN1_TIME *not_before = X509_get_notBefore(cert_profile->openssl_cert); ASN1_TIME_to_tm(not_before, ¬_before_time); strftime(not_before_str, sizeof(not_before_str), "%Y-%m-%dT%H:%M:%SZ", ¬_before_time); *value = dmstrdup(not_before_str); #elif LMBEDTLS struct certificate_profile *cert_profile = (struct certificate_profile*)data; dmasprintf(value, "%d-%d-%dT%d:%d:%dZ", cert_profile->mbdtls_cert.valid_from.year, cert_profile->mbdtls_cert.valid_from.mon, cert_profile->mbdtls_cert.valid_from.day, cert_profile->mbdtls_cert.valid_from.hour, cert_profile->mbdtls_cert.valid_from.min, cert_profile->mbdtls_cert.valid_from.sec); #endif return 0; } static int get_SecurityCertificate_NotAfter(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { *value = "0001-01-01T00:00:00Z"; #ifdef LOPENSSL struct tm not_after_time; struct certificate_profile *cert_profile = (struct certificate_profile*)data; char not_after_str[DATE_LEN]; ASN1_TIME *not_after = X509_get_notAfter(cert_profile->openssl_cert); ASN1_TIME_to_tm(not_after, ¬_after_time); strftime(not_after_str, sizeof(not_after_str), "%Y-%m-%dT%H:%M:%SZ", ¬_after_time); *value = dmstrdup(not_after_str); #elif LMBEDTLS struct certificate_profile *cert_profile = (struct certificate_profile*)data; dmasprintf(value, "%d-%d-%dT%d:%d:%dZ", cert_profile->mbdtls_cert.valid_to.year, cert_profile->mbdtls_cert.valid_to.mon, cert_profile->mbdtls_cert.valid_to.day, cert_profile->mbdtls_cert.valid_to.hour, cert_profile->mbdtls_cert.valid_to.min, cert_profile->mbdtls_cert.valid_to.sec); #endif return 0; } static int get_SecurityCertificate_Subject(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { *value = ""; #ifdef LOPENSSL struct certificate_profile *cert_profile = (struct certificate_profile*)data; *value = X509_NAME_oneline(X509_get_subject_name(cert_profile->openssl_cert), NULL, 0); if (*value[0] == '/') (*value)++; *value = replace_char(*value, '/', ' '); #elif LMBEDTLS struct certificate_profile *cert_profile = (struct certificate_profile*)data; size_t olen; unsigned char issuer[4096]; int ret2 = mbedtls_base64_encode(issuer, 4096, &olen, cert_profile->mbdtls_cert.subject.val.p, cert_profile->mbdtls_cert.subject.val.len ); if(ret2 != 0) return 0; *value = decode64(issuer); #endif return 0; } static int get_SecurityCertificate_SignatureAlgorithm(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { *value = ""; #ifdef LOPENSSL struct certificate_profile *cert_profile = (struct certificate_profile*)data; *value = dmstrdup(get_certificate_sig_alg(X509_get_signature_nid(cert_profile->openssl_cert))); #elif LMBEDTLS struct certificate_profile *cert_profile = (struct certificate_profile*)data; dmasprintf(value, "%sWith%sEncryptionn", get_certificate_md(cert_profile->mbdtls_cert.sig_md), get_certificate_pk(cert_profile->mbdtls_cert.sig_pk)); #endif return 0; } /* *** Device.Security. *** */ DMOBJ tSecurityObj[] = { /* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, nextobj, leaf, linker, bbfdm_type, uniqueKeys*/ {"Certificate", &DMREAD, NULL, NULL, NULL, browseSecurityCertificateInst, NULL, NULL, tSecurityCertificateParams, NULL, BBFDM_BOTH, LIST_KEY{"SerialNumber", "Issuer", NULL}}, {0} }; DMLEAF tSecurityParams[] = { /* PARAM, permission, type, getvalue, setvalue, bbfdm_type*/ {"CertificateNumberOfEntries", &DMREAD, DMT_UNINT, get_Security_CertificateNumberOfEntries, NULL, BBFDM_BOTH}, {0} }; /* *** Device.Security.Certificate.{i}. *** */ DMLEAF tSecurityCertificateParams[] = { /* PARAM, permission, type, getvalue, setvalue, bbfdm_type*/ //{"Enable", &DMWRITE, DMT_BOOL, get_SecurityCertificate_Enable, set_SecurityCertificate_Enable, BBFDM_BOTH}, {"LastModif", &DMREAD, DMT_TIME, get_SecurityCertificate_LastModif, NULL, BBFDM_BOTH}, {"SerialNumber", &DMREAD, DMT_STRING, get_SecurityCertificate_SerialNumber, NULL, BBFDM_BOTH}, {"Issuer", &DMREAD, DMT_STRING, get_SecurityCertificate_Issuer, NULL, BBFDM_BOTH}, {"NotBefore", &DMREAD, DMT_TIME, get_SecurityCertificate_NotBefore, NULL, BBFDM_BOTH}, {"NotAfter", &DMREAD, DMT_TIME, get_SecurityCertificate_NotAfter, NULL, BBFDM_BOTH}, {"Subject", &DMREAD, DMT_STRING, get_SecurityCertificate_Subject, NULL, BBFDM_BOTH}, //{"SubjectAlt", &DMREAD, DMT_STRING, get_SecurityCertificate_SubjectAlt, NULL, BBFDM_BOTH}, {"SignatureAlgorithm", &DMREAD, DMT_STRING, get_SecurityCertificate_SignatureAlgorithm, NULL, BBFDM_BOTH}, {0} };