From b32b13a196c92029ac7a861fbe23702ca81ce691 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20B=C3=A1rta?= Date: Mon, 15 Aug 2022 14:21:23 +0200 Subject: [PATCH] Move 3 functions to the appropriate util module. --- include/secutils/credentials/cert.h | 39 ----- include/secutils/util/util.h | 36 +++++ src/credentials/cert.c | 200 ------------------------- src/util/util.c | 220 +++++++++++++++++++++++++++- 4 files changed, 249 insertions(+), 246 deletions(-) diff --git a/include/secutils/credentials/cert.h b/include/secutils/credentials/cert.h index 1bf046a..f831362 100644 --- a/include/secutils/credentials/cert.h +++ b/include/secutils/credentials/cert.h @@ -99,19 +99,6 @@ int CERTS_save(OPTIONAL const STACK_OF(X509) *certs, const char *file, OPTIONAL void CERTS_free(OPTIONAL STACK_OF(X509) *certs); -/*!***************************************************************************** - * @brief parse an X.500 Distinguished Name (DN) - * - * @param dn string to be parsed, format "/type0=value0/type1=value1/type2=..." where characters may be escaped by '\'. - * The NULL-DN may be given as "/" or "". - * @param chtype type of the string, e.g., MBSTRING_ASC, as defined in openssl/asn1.h - * @param multirdn flag whether to allow multi-valued RDNs - * @return ASN.1 representation of the DN, or null on error - *******************************************************************************/ -/* this function is used by the genCMPClient API implementation */ -X509_NAME* UTIL_parse_name(const char* dn, long chtype, bool multirdn); - - /*!***************************************************************************** * @brief log messsage about the given certificate, printing its subject * @@ -177,30 +164,4 @@ bool CERT_check_all(const char *uri, OPTIONAL STACK_OF(X509) *certs, int type_CA OPTIONAL const X509_VERIFY_PARAM *vpm); -/*!***************************************************************************** - * @brief add certificate to given stack, optionally only if not already contained - * - * @param sk stack of certificates - * @param cert certificate to be pushed to the stack - * @param no_duplicate flag governing whether to add cert if it is a duplicate - * @return true on success, else false - *******************************************************************************/ -bool UTIL_sk_X509_add1_cert(STACK_OF(X509) * sk, X509* cert, bool no_duplicate); - - -/*!***************************************************************************** - * @brief add stack of certificates to given stack, - * optionally only if not self-signed and optionally if not already contained - * - * @param sk stack of certificates - * @param certs (optional) stack of certificates to be pushed to the stack - * @param no_self_signed flag governing whether to add self-signed certs - * @param no_duplicates flag governing whether to add cert if it is a duplicate - * @return true on success, else false - *******************************************************************************/ -/* this function is used by the genCMPClient API implementation */ -int UTIL_sk_X509_add1_certs(STACK_OF(X509) * sk, OPTIONAL const STACK_OF(X509) * certs, int no_self_signed, - int no_duplicates); - - #endif /* SECUTILS_CERT_H_ */ diff --git a/include/secutils/util/util.h b/include/secutils/util/util.h index 11c82fc..c6aace1 100644 --- a/include/secutils/util/util.h +++ b/include/secutils/util/util.h @@ -195,6 +195,30 @@ typedef u_int64_t uint64_t; STACK_OF(X509) *X509_STORE_get1_all_certs(X509_STORE *store); # endif +/*!***************************************************************************** + * @brief add certificate to given stack, optionally only if not already contained + * + * @param sk stack of certificates + * @param cert certificate to be pushed to the stack + * @param no_duplicate flag governing whether to add cert if it is a duplicate + * @return true on success, else false + *******************************************************************************/ +bool UTIL_sk_X509_add1_cert(STACK_OF(X509) * sk, X509* cert, bool no_duplicate); + +/*!***************************************************************************** + * @brief add stack of certificates to given stack, + * optionally only if not self-signed and optionally if not already contained + * + * @param sk stack of certificates + * @param certs (optional) stack of certificates to be pushed to the stack + * @param no_self_signed flag governing whether to add self-signed certs + * @param no_duplicates flag governing whether to add cert if it is a duplicate + * @return true on success, else false + *******************************************************************************/ +/* this function is used by the genCMPClient API implementation */ +int UTIL_sk_X509_add1_certs(STACK_OF(X509) * sk, OPTIONAL const STACK_OF(X509) * certs, int no_self_signed, + int no_duplicates); + /*!***************************************************************************** * @brief initialize the OpenSSL crypto library * @param version expected OpenSSL version number @@ -262,6 +286,18 @@ void *UTIL_read_file(const char *filename, int *lenp); ******************************************************************************/ bool UTIL_write_file(const char *filename, const void *data, size_t len); +/*!***************************************************************************** + * @brief parse an X.500 Distinguished Name (DN) + * + * @param dn string to be parsed, format "/type0=value0/type1=value1/type2=..." where characters may be escaped by '\'. + * The NULL-DN may be given as "/" or "". + * @param chtype type of the string, e.g., MBSTRING_ASC, as defined in openssl/asn1.h + * @param multirdn flag whether to allow multi-valued RDNs + * @return ASN.1 representation of the DN, or null on error + *******************************************************************************/ +/* this function is used by the genCMPClient API implementation */ +X509_NAME* UTIL_parse_name(const char* dn, long chtype, bool multirdn); + /*!***************************************************************************** * @brief call given function on each file in dir, optionally with recursion * @param fn function to be called on each file. diff --git a/src/credentials/cert.c b/src/credentials/cert.c index bc16638..c14b19f 100644 --- a/src/credentials/cert.c +++ b/src/credentials/cert.c @@ -71,151 +71,6 @@ void CERTS_free(OPTIONAL STACK_OF(X509) *certs) sk_X509_pop_free(certs, X509_free); } -/* - * dn is expected to be in the format "/type0=value0/type1=value1/type2=..." - * where characters may be escaped by '\'. - * The NULL-DN may be given as "/" or "". - */ -/* adapted from OpenSSL:apps/lib/apps.c */ -X509_NAME* UTIL_parse_name(const char* dn, long chtype, bool multirdn) -{ - size_t buflen = strlen(dn) + 1; /* to copy the types and values. - * Due to escaping, the copy can only become shorter */ - char* buf = OPENSSL_malloc(buflen); - size_t max_ne = buflen / (1 + 1) + 1; /* maximum number of name elements */ - const char** ne_types = OPENSSL_malloc(max_ne * sizeof(char*)); - char** ne_values = OPENSSL_malloc(max_ne * sizeof(char*)); - int* mval = OPENSSL_malloc(max_ne * sizeof(int)); - - const char* sp = dn; - char* bp = buf; - int i, ne_num = 0; - - X509_NAME* n = 0; - int nid; - - if(0 is_eq buf or 0 is_eq ne_types or 0 is_eq ne_values or 0 is_eq mval) - { - LOG_err("Malloc error"); - goto error; - } - - /* no multivalued RDN by default */ - mval[ne_num] = 0; - - if(*sp not_eq '\0' and *sp++ not_eq '/') - { /* skip leading '/' */ - LOG(FL_ERR, "DN '%s' does not start with '/'.", dn); - goto error; - } - - while(*sp not_eq '\0') - { - /* collect type */ - ne_types[ne_num] = bp; - /* parse element name */ - while(*sp not_eq '=') - { - if(*sp is_eq '\\') - { /* is there anything to escape in the * type...? */ - if(*++sp not_eq '\0') - { - *bp++ = *sp++; - } - else - { - LOG(FL_ERR, "Escape character at end of DN '%s'", dn); - goto error; - } - } - else if(*sp is_eq '\0') - { - LOG(FL_ERR, "End of string encountered while processing type of DN '%s' element #%d", dn, ne_num); - goto error; - } - else - { - *bp++ = *sp++; - } - } - sp++; - *bp++ = '\0'; - /* parse element value */ - ne_values[ne_num] = bp; - while(*sp not_eq '\0') - { - if(*sp is_eq '\\') - { - if(*++sp not_eq '\0') - { - *bp++ = *sp++; - } - else - { - LOG(FL_ERR, "Escape character at end of DN '%s'", dn); - goto error; - } - } - else if(*sp is_eq '/') - { /* start of next element */ - sp++; - /* no multivalued RDN by default */ - mval[ne_num + 1] = 0; - break; - } - else if(*sp is_eq '+' and multirdn) - { - /* a not escaped + signals a multi-valued RDN */ - sp++; - mval[ne_num + 1] = -1; - break; - } - else - { - *bp++ = *sp++; - } - } - *bp++ = '\0'; - ne_num++; - } - - if(0 is_eq(n = X509_NAME_new())) - { - goto error; - } - - for(i = 0; i < ne_num; i++) - { - if((nid = OBJ_txt2nid(ne_types[i])) is_eq NID_undef) - { - LOG(FL_WARN, "DN '%s' attribute %s has no known NID, skipped", dn, ne_types[i]); - continue; - } - - if(0 is_eq * ne_values[i]) - { - LOG(FL_WARN, "No value provided for DN '%s' attribute %s, skipped", dn, ne_types[i]); - continue; - } - - if(0 is_eq X509_NAME_add_entry_by_NID(n, nid, chtype, (unsigned char*)ne_values[i], -1, -1, mval[i])) - { - ERR_print_errors(bio_err); - LOG(FL_ERR, "Error adding name attribute '/%s=%s'", ne_types[i], ne_values[i]); - X509_NAME_free(n); - n = 0; - goto error; - } - } - -error: - OPENSSL_free(ne_values); - OPENSSL_free(ne_types); - OPENSSL_free(mval); - OPENSSL_free(buf); - return n; -} - void CERT_print(OPTIONAL const X509* cert, OPTIONAL BIO* bio, unsigned long neg_cflags) { @@ -362,58 +217,3 @@ bool CERT_check_all(const char *uri, OPTIONAL STACK_OF(X509) *certs, int type_CA && ret; /* Having 'ret' after the '&&', all certs are checked. */ return ret; } - - -/* start of definitions borrowed from OpenSSL:crypto/cmp/cmp_lib.c */ -static int X509_cmp_from_ptrs(const struct x509_st* const* a, const struct x509_st* const* b) -{ - return X509_cmp(*a, *b); -} - -bool UTIL_sk_X509_add1_cert(STACK_OF(X509) * sk, X509* cert, bool no_duplicate) -{ - if(no_duplicate) - { - sk_X509_set_cmp_func(sk, &X509_cmp_from_ptrs); - if(sk_X509_find(sk, cert) >= 0) - { - return 1; - } - } - if(0 is_eq sk_X509_push(sk, cert)) - { - return 0; - } - return X509_up_ref(cert); -} - -int UTIL_sk_X509_add1_certs(STACK_OF(X509) * sk, OPTIONAL const STACK_OF(X509) * certs, int no_self_signed, - int no_duplicates) -{ - int i = 0; - - if(sk is_eq 0) - { - return 0; - } - - if(certs is_eq 0) - { - return 1; - } - const int n = sk_X509_num(certs); - for(i = 0; i < n; i++) - { - X509* cert = sk_X509_value(certs, i); - if((not no_self_signed or X509_check_issued(cert, cert) not_eq X509_V_OK) - and (not UTIL_sk_X509_add1_cert(sk, cert, no_duplicates))) - { - return 0; - } - } - return 1; -} -/* end of definitions borrowed from OpenSSL:crypto/cmp/cmp_lib.c */ - - - diff --git a/src/util/util.c b/src/util/util.c index 5c1d3c3..b337d6b 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -181,6 +181,7 @@ bool UTIL_write_file(const char* filename, const void* data, size_t len) bool UTIL_iterate_dir(bool (*fn)(const char* file, void* arg), void* arg, const char* path, bool recursive) { bool res = false; + int i; if(0 is_eq fn or 0 is_eq path) { @@ -188,16 +189,18 @@ bool UTIL_iterate_dir(bool (*fn)(const char* file, void* arg), void* arg, const return false; } - DIR* p_dir = opendir(path); - if(0 == p_dir) + struct dirent** namelist = 0; + const int count = scandir(path, &namelist, 0, alphasort); + if(-1 is_eq count) { LOG(FL_ERR, "cannot open directory '%s'", path); return false; } - struct dirent* p_dirent = readdir(p_dir); - while(0 not_eq p_dirent) + for(i = 0; i < count; ++i) { + const struct dirent* p_dirent = namelist[i]; + char full_path[UTIL_max_path_len]; /* constant 2 takes into account end of string and format string content */ snprintf(full_path, sizeof(full_path), "%.*s/%.*s", UTIL_max_path_len - UTIL_max_name_len - 2, path, @@ -207,7 +210,7 @@ bool UTIL_iterate_dir(bool (*fn)(const char* file, void* arg), void* arg, const memset(&f_stat, 0x00, sizeof(f_stat)); if(-1 is_eq stat(full_path, &f_stat)) { - LOG(FL_INFO, "cannot read status of %s - %s", full_path, strerror(errno)); + LOG(FL_WARN, "cannot read status of %s - %s", full_path, strerror(errno)); } else { @@ -226,16 +229,166 @@ bool UTIL_iterate_dir(bool (*fn)(const char* file, void* arg), void* arg, const } } } - p_dirent = readdir(p_dir); } res = true; err: - closedir(p_dir); + for(i = 0; i < count; ++i) + { + free(namelist[i]); + } + free(namelist); + return res; } +/* + * dn is expected to be in the format "/type0=value0/type1=value1/type2=..." + * where characters may be escaped by '\'. + * The NULL-DN may be given as "/" or "". + */ +/* adapted from OpenSSL:apps/lib/apps.c */ +X509_NAME* UTIL_parse_name(const char* dn, long chtype, bool multirdn) +{ + size_t buflen = strlen(dn) + 1; /* to copy the types and values. + * Due to escaping, the copy can only become shorter */ + char* buf = OPENSSL_malloc(buflen); + size_t max_ne = buflen / (1 + 1) + 1; /* maximum number of name elements */ + const char** ne_types = OPENSSL_malloc(max_ne * sizeof(char*)); + char** ne_values = OPENSSL_malloc(max_ne * sizeof(char*)); + int* mval = OPENSSL_malloc(max_ne * sizeof(int)); + + const char* sp = dn; + char* bp = buf; + int i, ne_num = 0; + + X509_NAME* n = 0; + int nid; + + if(0 is_eq buf or 0 is_eq ne_types or 0 is_eq ne_values or 0 is_eq mval) + { + LOG_err("Malloc error"); + goto error; + } + + /* no multivalued RDN by default */ + mval[ne_num] = 0; + + if(*sp not_eq '\0' and *sp++ not_eq '/') + { /* skip leading '/' */ + LOG(FL_ERR, "DN '%s' does not start with '/'.", dn); + goto error; + } + + while(*sp not_eq '\0') + { + /* collect type */ + ne_types[ne_num] = bp; + /* parse element name */ + while(*sp not_eq '=') + { + if(*sp is_eq '\\') + { /* is there anything to escape in the * type...? */ + if(*++sp not_eq '\0') + { + *bp++ = *sp++; + } + else + { + LOG(FL_ERR, "Escape character at end of DN '%s'", dn); + goto error; + } + } + else if(*sp is_eq '\0') + { + LOG(FL_ERR, "End of string encountered while processing type of DN '%s' element #%d", dn, ne_num); + goto error; + } + else + { + *bp++ = *sp++; + } + } + sp++; + *bp++ = '\0'; + /* parse element value */ + ne_values[ne_num] = bp; + while(*sp not_eq '\0') + { + if(*sp is_eq '\\') + { + if(*++sp not_eq '\0') + { + *bp++ = *sp++; + } + else + { + LOG(FL_ERR, "Escape character at end of DN '%s'", dn); + goto error; + } + } + else if(*sp is_eq '/') + { /* start of next element */ + sp++; + /* no multivalued RDN by default */ + mval[ne_num + 1] = 0; + break; + } + else if(*sp is_eq '+' and multirdn) + { + /* a not escaped + signals a multi-valued RDN */ + sp++; + mval[ne_num + 1] = -1; + break; + } + else + { + *bp++ = *sp++; + } + } + *bp++ = '\0'; + ne_num++; + } + + if(0 is_eq(n = X509_NAME_new())) + { + goto error; + } + + for(i = 0; i < ne_num; i++) + { + if((nid = OBJ_txt2nid(ne_types[i])) is_eq NID_undef) + { + LOG(FL_WARN, "DN '%s' attribute %s has no known NID, skipped", dn, ne_types[i]); + continue; + } + + if(0 is_eq * ne_values[i]) + { + LOG(FL_WARN, "No value provided for DN '%s' attribute %s, skipped", dn, ne_types[i]); + continue; + } + + if(0 is_eq X509_NAME_add_entry_by_NID(n, nid, chtype, (unsigned char*)ne_values[i], -1, -1, mval[i])) + { + ERR_print_errors(bio_err); + LOG(FL_ERR, "Error adding name attribute '/%s=%s'", ne_types[i], ne_values[i]); + X509_NAME_free(n); + n = 0; + goto error; + } + } + +error: + OPENSSL_free(ne_values); + OPENSSL_free(ne_types); + OPENSSL_free(mval); + OPENSSL_free(buf); + return n; +} + + void UTIL_erase_mem(void* dst, size_t len) { if(dst not_eq 0) @@ -325,6 +478,59 @@ int ASN1_TIME_compare(const ASN1_TIME *a, const ASN1_TIME *b) } #endif + +/* start of definitions borrowed from OpenSSL:crypto/cmp/cmp_lib.c */ +static int X509_cmp_from_ptrs(const struct x509_st* const* a, const struct x509_st* const* b) +{ + return X509_cmp(*a, *b); +} + +bool UTIL_sk_X509_add1_cert(STACK_OF(X509) * sk, X509* cert, bool no_duplicate) +{ + if(no_duplicate) + { + sk_X509_set_cmp_func(sk, &X509_cmp_from_ptrs); + if(sk_X509_find(sk, cert) >= 0) + { + return 1; + } + } + if(0 is_eq sk_X509_push(sk, cert)) + { + return 0; + } + return X509_up_ref(cert); +} + +int UTIL_sk_X509_add1_certs(STACK_OF(X509) * sk, OPTIONAL const STACK_OF(X509) * certs, int no_self_signed, + int no_duplicates) +{ + int i = 0; + + if(sk is_eq 0) + { + return 0; + } + + if(certs is_eq 0) + { + return 1; + } + const int n = sk_X509_num(certs); + for(i = 0; i < n; i++) + { + X509* cert = sk_X509_value(certs, i); + if((not no_self_signed or X509_check_issued(cert, cert) not_eq X509_V_OK) + and (not UTIL_sk_X509_add1_cert(sk, cert, no_duplicates))) + { + return 0; + } + } + return 1; +} +/* end of definitions borrowed from OpenSSL:crypto/cmp/cmp_lib.c */ + + /* Copy a NUL-terminated string from the given source * into an optional destination buffer, or calculate how large it needs to be. * Copy at most destination_len bytes including the terminating NUL.