X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fconf%2Fconf_def.c;h=26764dad00421a9b6503c2a8cf82966342a2d0e7;hp=1d34519d1aa5f29615cab735191551477a01093c;hb=HEAD;hpb=454afd9866300b984306c5b565a9d55568a5bc50 diff --git a/crypto/conf/conf_def.c b/crypto/conf/conf_def.c index 1d34519d1a..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,11 +11,17 @@ #include #include +#include "internal/e_os.h" /* struct stat */ +#ifdef __TANDEM +# 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 @@ -23,12 +29,9 @@ # include # ifdef _WIN32 # define stat _stat -# define strcasecmp _stricmp # endif #endif -DEFINE_STACK_OF(BIO) - #ifndef S_ISDIR # define S_ISDIR(a) (((a) & S_IFMT) == S_IFDIR) #endif @@ -173,9 +176,9 @@ static int def_load(CONF *conf, const char *name, long *line) #endif if (in == NULL) { if (ERR_GET_REASON(ERR_peek_last_error()) == BIO_R_NO_SUCH_FILE) - CONFerr(CONF_F_DEF_LOAD, CONF_R_NO_SUCH_FILE); + ERR_raise(ERR_LIB_CONF, CONF_R_NO_SUCH_FILE); else - CONFerr(CONF_F_DEF_LOAD, ERR_R_SYS_LIB); + ERR_raise(ERR_LIB_CONF, ERR_R_SYS_LIB); return 0; } @@ -185,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 */ @@ -193,6 +213,7 @@ static int def_load_bio(CONF *conf, BIO *in, long *line) BUF_MEM *buff = NULL; char *s, *p, *end; int again; + int first_call = 1; long eline = 0; char btmp[DECIMAL_SIZE(eline) + 1]; CONF_VALUE *v = NULL, *tv; @@ -205,26 +226,27 @@ 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) { - CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_BUF_LIB); + ERR_raise(ERR_LIB_CONF, ERR_R_BUF_LIB); goto err; } section = OPENSSL_strdup("default"); - if (section == NULL) { - CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE); + if (section == NULL) goto err; - } if (_CONF_new_data(conf) == 0) { - CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_CONF, ERR_R_CONF_LIB); goto err; } sv = _CONF_new_section(conf, section); if (sv == NULL) { - CONFerr(CONF_F_DEF_LOAD_BIO, CONF_R_UNABLE_TO_CREATE_NEW_SECTION); + ERR_raise(ERR_LIB_CONF, CONF_R_UNABLE_TO_CREATE_NEW_SECTION); goto err; } @@ -232,17 +254,31 @@ static int def_load_bio(CONF *conf, BIO *in, long *line) again = 0; for (;;) { if (!BUF_MEM_grow(buff, bufnum + CONFBUFSIZE)) { - CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_BUF_LIB); + ERR_raise(ERR_LIB_CONF, ERR_R_BUF_LIB); goto err; } p = &(buff->data[bufnum]); *p = '\0'; read_retry: - BIO_gets(in, p, CONFBUFSIZE - 1); + if (in != NULL && BIO_gets(in, p, CONFBUFSIZE - 1) < 0) + goto err; p[CONFBUFSIZE - 1] = '\0'; ii = i = strlen(p); + if (first_call) { + /* Other BOMs imply unsupported multibyte encoding, + * so don't strip them and let the error raise */ + const unsigned char utf8_bom[3] = {0xEF, 0xBB, 0xBF}; + + if (i >= 3 && memcmp(p, utf8_bom, 3) == 0) { + memmove(p, p + 3, i - 3); + p[i - 3] = 0; + i -= 3; + ii -= 3; + } + first_call = 0; + } if (i == 0 && !again) { - /* the currently processed BIO is at EOF */ + /* the currently processed BIO is NULL or at EOF */ BIO *parent; #ifndef OPENSSL_NO_POSIX_IO @@ -328,8 +364,7 @@ static int def_load_bio(CONF *conf, BIO *in, long *line) ss = p; goto again; } - CONFerr(CONF_F_DEF_LOAD_BIO, - CONF_R_MISSING_CLOSE_SQUARE_BRACKET); + ERR_raise(ERR_LIB_CONF, CONF_R_MISSING_CLOSE_SQUARE_BRACKET); goto err; } *end = '\0'; @@ -338,8 +373,7 @@ static int def_load_bio(CONF *conf, BIO *in, long *line) if ((sv = _CONF_get_section(conf, section)) == NULL) sv = _CONF_new_section(conf, section); if (sv == NULL) { - CONFerr(CONF_F_DEF_LOAD_BIO, - CONF_R_UNABLE_TO_CREATE_NEW_SECTION); + ERR_raise(ERR_LIB_CONF, CONF_R_UNABLE_TO_CREATE_NEW_SECTION); goto err; } continue; @@ -356,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 == '=') { @@ -369,7 +403,7 @@ static int def_load_bio(CONF *conf, BIO *in, long *line) /* Pragma values take the form keyword:value */ pval = strchr(p, ':'); if (pval == NULL || pval == p || pval[1] == '\0') { - CONFerr(CONF_F_DEF_LOAD_BIO, CONF_R_INVALID_PRAGMA); + ERR_raise(ERR_LIB_CONF, CONF_R_INVALID_PRAGMA); goto err; } @@ -381,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 { - CONFerr(CONF_F_DEF_LOAD_BIO, 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); @@ -413,18 +466,31 @@ static int def_load_bio(CONF *conf, BIO *in, long *line) if (!str_copy(conf, psection, &include, p)) goto err; - if (include_dir != NULL) { + if (include_dir != NULL && !ossl_is_absolute_path(include)) { size_t newlen = strlen(include_dir) + strlen(include) + 2; include_path = OPENSSL_malloc(newlen); + if (include_path == NULL) { + OPENSSL_free(include); + goto err; + } + OPENSSL_strlcpy(include_path, include_dir, newlen); - OPENSSL_strlcat(include_path, "/", newlen); + if (!ossl_ends_with_dirsep(include_path)) + OPENSSL_strlcat(include_path, "/", newlen); OPENSSL_strlcat(include_path, include, newlen); OPENSSL_free(include); } else { 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); @@ -441,12 +507,14 @@ 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) { - CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_CONF, ERR_R_CRYPTO_LIB); + BIO_free(next); goto err; } } if (!sk_BIO_push(biosk, in)) { - CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_CONF, ERR_R_CRYPTO_LIB); + BIO_free(next); goto err; } /* continue with reading from the included BIO */ @@ -454,8 +522,8 @@ static int def_load_bio(CONF *conf, BIO *in, long *line) } continue; } else if (*p != '=') { - CONFerr(CONF_F_DEF_LOAD_BIO, CONF_R_MISSING_EQUAL_SIGN); - ERR_add_error_data(2, "HERE-->", p); + ERR_raise_data(ERR_LIB_CONF, CONF_R_MISSING_EQUAL_SIGN, + "HERE-->%s", p); goto err; } *end = '\0'; @@ -463,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) { - CONFerr(CONF_F_DEF_LOAD_BIO, 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) { - CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE); + if (v->name == NULL) goto err; - } if (!str_copy(conf, psection, &(v->value), start)) goto err; @@ -481,14 +545,14 @@ static int def_load_bio(CONF *conf, BIO *in, long *line) == NULL) tv = _CONF_new_section(conf, psection); if (tv == NULL) { - CONFerr(CONF_F_DEF_LOAD_BIO, - CONF_R_UNABLE_TO_CREATE_NEW_SECTION); + ERR_raise(ERR_LIB_CONF, + CONF_R_UNABLE_TO_CREATE_NEW_SECTION); goto err; } } else tv = sv; if (_CONF_add_string(conf, tv, v) == 0) { - CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_CONF, ERR_R_CONF_LIB); goto err; } v = NULL; @@ -502,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); @@ -671,7 +736,7 @@ static int str_copy(CONF *conf, char *section, char **pto, char *from) rp = e; if (q) { if (r != q) { - CONFerr(CONF_F_STR_COPY, CONF_R_NO_CLOSE_BRACE); + ERR_raise(ERR_LIB_CONF, CONF_R_NO_CLOSE_BRACE); goto err; } e++; @@ -691,16 +756,16 @@ static int str_copy(CONF *conf, char *section, char **pto, char *from) *rrp = rr; *rp = r; if (p == NULL) { - CONFerr(CONF_F_STR_COPY, CONF_R_VARIABLE_HAS_NO_VALUE); + ERR_raise(ERR_LIB_CONF, CONF_R_VARIABLE_HAS_NO_VALUE); goto err; } newsize = strlen(p) + buf->length - (e - from); if (newsize > MAX_CONF_VALUE_LENGTH) { - CONFerr(CONF_F_STR_COPY, CONF_R_VARIABLE_EXPANSION_TOO_LONG); + ERR_raise(ERR_LIB_CONF, CONF_R_VARIABLE_EXPANSION_TOO_LONG); goto err; } if (!BUF_MEM_grow_clean(buf, newsize)) { - CONFerr(CONF_F_STR_COPY, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_CONF, ERR_R_BUF_LIB); goto err; } while (*p) @@ -745,18 +810,15 @@ static BIO *process_include(char *include, OPENSSL_DIR_CTX **dirctx, BIO *next; if (stat(include, &st) < 0) { - ERR_raise_data(ERR_LIB_SYS, errno, - "calling stat(%s)", - include); + ERR_raise_data(ERR_LIB_SYS, errno, "calling stat(%s)", include); /* missing include file is not fatal error */ return NULL; } if (S_ISDIR(st.st_mode)) { if (*dirctx != NULL) { - CONFerr(CONF_F_PROCESS_INCLUDE, - CONF_R_RECURSIVE_DIRECTORY_INCLUDE); - ERR_add_error_data(1, include); + ERR_raise_data(ERR_LIB_CONF, CONF_R_RECURSIVE_DIRECTORY_INCLUDE, + "%s", include); return NULL; } /* a directory, load its contents */ @@ -785,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) { - CONFerr(CONF_F_GET_NEXT_FILE, ERR_R_MALLOC_FAILURE); + if (newpath == NULL) break; - } #ifdef OPENSSL_SYS_VMS /* * If the given path isn't clear VMS syntax, @@ -830,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