X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fconf%2Fconf_def.c;h=26764dad00421a9b6503c2a8cf82966342a2d0e7;hp=99063eaf68c3eb1c0b84b2f10f796bd2f98408c0;hb=HEAD;hpb=4369a882a565c42673b28c586a5c46a8bca98d17 diff --git a/crypto/conf/conf_def.c b/crypto/conf/conf_def.c index 99063eaf68..e047746f67 100644 --- a/crypto/conf/conf_def.c +++ b/crypto/conf/conf_def.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -11,14 +11,17 @@ #include #include +#include "internal/e_os.h" /* struct stat */ #ifdef __TANDEM -# include /* strcasecmp */ +# include /* needed for stat.h */ +# include /* struct stat */ #endif #include "internal/cryptlib.h" #include "internal/o_dir.h" #include #include #include +#include "conf_local.h" #include "conf_def.h" #include #include @@ -26,7 +29,6 @@ # include # ifdef _WIN32 # define stat _stat -# define strcasecmp _stricmp # endif #endif @@ -186,6 +188,23 @@ static int def_load(CONF *conf, const char *name, long *line) return ret; } + +/* Parse a boolean value and fill in *flag. Return 0 on error. */ +static int parsebool(const char *pval, int *flag) +{ + if (OPENSSL_strcasecmp(pval, "on") == 0 + || OPENSSL_strcasecmp(pval, "true") == 0) { + *flag = 1; + } else if (OPENSSL_strcasecmp(pval, "off") == 0 + || OPENSSL_strcasecmp(pval, "false") == 0) { + *flag = 0; + } else { + ERR_raise(ERR_LIB_CONF, CONF_R_INVALID_PRAGMA); + return 0; + } + return 1; +} + static int def_load_bio(CONF *conf, BIO *in, long *line) { /* The macro BUFSIZE conflicts with a system macro in VxWorks */ @@ -207,6 +226,9 @@ static int def_load_bio(CONF *conf, BIO *in, long *line) char *dirpath = NULL; OPENSSL_DIR_CTX *dirctx = NULL; #endif +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + int numincludes = 0; +#endif if ((buff = BUF_MEM_new()) == NULL) { ERR_raise(ERR_LIB_CONF, ERR_R_BUF_LIB); @@ -214,13 +236,11 @@ static int def_load_bio(CONF *conf, BIO *in, long *line) } section = OPENSSL_strdup("default"); - if (section == NULL) { - ERR_raise(ERR_LIB_CONF, ERR_R_MALLOC_FAILURE); + if (section == NULL) goto err; - } if (_CONF_new_data(conf) == 0) { - ERR_raise(ERR_LIB_CONF, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_CONF, ERR_R_CONF_LIB); goto err; } @@ -370,8 +390,8 @@ static int def_load_bio(CONF *conf, BIO *in, long *line) psection = section; } p = eat_ws(conf, end); - if (strncmp(pname, ".pragma", 7) == 0 - && (p != pname + 7 || *p == '=')) { + if (CHECK_AND_SKIP_PREFIX(pname, ".pragma") + && (p != pname || *p == '=')) { char *pval; if (*p == '=') { @@ -395,30 +415,49 @@ static int def_load_bio(CONF *conf, BIO *in, long *line) * Known pragmas: * * dollarid takes "on", "true or "off", "false" + * abspath takes "on", "true or "off", "false" + * includedir directory prefix */ if (strcmp(p, "dollarid") == 0) { - if (strcmp(pval, "on") == 0 - || strcmp(pval, "true") == 0) { - conf->flag_dollarid = 1; - } else if (strcmp(pval, "off") == 0 - || strcmp(pval, "false") == 0) { - conf->flag_dollarid = 0; - } else { - ERR_raise(ERR_LIB_CONF, CONF_R_INVALID_PRAGMA); + if (!parsebool(pval, &conf->flag_dollarid)) + goto err; + } else if (strcmp(p, "abspath") == 0) { + if (!parsebool(pval, &conf->flag_abspath)) + goto err; + } else if (strcmp(p, "includedir") == 0) { + OPENSSL_free(conf->includedir); + if ((conf->includedir = OPENSSL_strdup(pval)) == NULL) goto err; - } } + /* * We *ignore* any unknown pragma. */ continue; - } else if (strncmp(pname, ".include", 8) == 0 - && (p != pname + 8 || *p == '=')) { + } else if (CHECK_AND_SKIP_PREFIX(pname, ".include") + && (p != pname || *p == '=')) { char *include = NULL; BIO *next; const char *include_dir = ossl_safe_getenv("OPENSSL_CONF_INCLUDE"); char *include_path = NULL; +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* + * The include processing below can cause the "conf" fuzzer to + * timeout due to the fuzzer inserting large and complicated + * includes - with a large amount of time spent in + * OPENSSL_strlcat/OPENSSL_strcpy. This is not a security + * concern because config files should never come from untrusted + * sources. We just set an arbitrary limit on the allowed + * number of includes when fuzzing to prevent this timeout. + */ + if (numincludes++ > 10) + goto err; +#endif + + if (include_dir == NULL) + include_dir = conf->includedir; + if (*p == '=') { p++; p = eat_ws(conf, p); @@ -432,7 +471,6 @@ static int def_load_bio(CONF *conf, BIO *in, long *line) include_path = OPENSSL_malloc(newlen); if (include_path == NULL) { - ERR_raise(ERR_LIB_CONF, ERR_R_MALLOC_FAILURE); OPENSSL_free(include); goto err; } @@ -446,6 +484,13 @@ static int def_load_bio(CONF *conf, BIO *in, long *line) include_path = include; } + if (conf->flag_abspath + && !ossl_is_absolute_path(include_path)) { + ERR_raise(ERR_LIB_CONF, CONF_R_RELATIVE_PATH); + OPENSSL_free(include_path); + goto err; + } + /* get the BIO of the included file */ #ifndef OPENSSL_NO_POSIX_IO next = process_include(include_path, &dirctx, &dirpath); @@ -462,13 +507,13 @@ static int def_load_bio(CONF *conf, BIO *in, long *line) /* push the currently processing BIO onto stack */ if (biosk == NULL) { if ((biosk = sk_BIO_new_null()) == NULL) { - ERR_raise(ERR_LIB_CONF, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_CONF, ERR_R_CRYPTO_LIB); BIO_free(next); goto err; } } if (!sk_BIO_push(biosk, in)) { - ERR_raise(ERR_LIB_CONF, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_CONF, ERR_R_CRYPTO_LIB); BIO_free(next); goto err; } @@ -486,16 +531,12 @@ static int def_load_bio(CONF *conf, BIO *in, long *line) start = eat_ws(conf, p); trim_ws(conf, start); - if ((v = OPENSSL_malloc(sizeof(*v))) == NULL) { - ERR_raise(ERR_LIB_CONF, ERR_R_MALLOC_FAILURE); + if ((v = OPENSSL_malloc(sizeof(*v))) == NULL) goto err; - } v->name = OPENSSL_strdup(pname); v->value = NULL; - if (v->name == NULL) { - ERR_raise(ERR_LIB_CONF, ERR_R_MALLOC_FAILURE); + if (v->name == NULL) goto err; - } if (!str_copy(conf, psection, &(v->value), start)) goto err; @@ -511,7 +552,7 @@ static int def_load_bio(CONF *conf, BIO *in, long *line) } else tv = sv; if (_CONF_add_string(conf, tv, v) == 0) { - ERR_raise(ERR_LIB_CONF, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_CONF, ERR_R_CONF_LIB); goto err; } v = NULL; @@ -525,6 +566,7 @@ static int def_load_bio(CONF *conf, BIO *in, long *line) */ sk_BIO_free(biosk); return 1; + err: BUF_MEM_free(buff); OPENSSL_free(section); @@ -723,7 +765,7 @@ static int str_copy(CONF *conf, char *section, char **pto, char *from) goto err; } if (!BUF_MEM_grow_clean(buf, newsize)) { - ERR_raise(ERR_LIB_CONF, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_CONF, ERR_R_BUF_LIB); goto err; } while (*p) @@ -805,18 +847,18 @@ static BIO *get_next_file(const char *path, OPENSSL_DIR_CTX **dirctx) namelen = strlen(filename); - if ((namelen > 5 && strcasecmp(filename + namelen - 5, ".conf") == 0) - || (namelen > 4 && strcasecmp(filename + namelen - 4, ".cnf") == 0)) { + if ((namelen > 5 + && OPENSSL_strcasecmp(filename + namelen - 5, ".conf") == 0) + || (namelen > 4 + && OPENSSL_strcasecmp(filename + namelen - 4, ".cnf") == 0)) { size_t newlen; char *newpath; BIO *bio; newlen = pathlen + namelen + 2; newpath = OPENSSL_zalloc(newlen); - if (newpath == NULL) { - ERR_raise(ERR_LIB_CONF, ERR_R_MALLOC_FAILURE); + if (newpath == NULL) break; - } #ifdef OPENSSL_SYS_VMS /* * If the given path isn't clear VMS syntax, @@ -850,7 +892,7 @@ static BIO *get_next_file(const char *path, OPENSSL_DIR_CTX **dirctx) static int is_keytype(const CONF *conf, char c, unsigned short type) { - const unsigned short * keytypes = (const unsigned short *) conf->meth_data; + const unsigned short *keytypes = (const unsigned short *) conf->meth_data; unsigned char key = (unsigned char)c; #ifdef CHARSET_EBCDIC