DECODER: use property definitions instead of getting implementation parameters
[openssl.git] / crypto / err / err.c
index eca0f6d33e79a8830019f3ffdead3c4cc70a97a9..9b1a15d5bdf8bb6ec8f65691a777ad17520e840b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2021 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
@@ -7,7 +7,6 @@
  * https://www.openssl.org/source/license.html
  */
 
-/* TODO: When ERR_STATE becomes opaque, this musts be removed */
 #define OSSL_FORCE_ERR_STATE
 
 #include <stdio.h>
@@ -70,10 +69,14 @@ static ERR_STRING_DATA ERR_str_libraries[] = {
     {ERR_PACK(ERR_LIB_HMAC, 0, 0), "HMAC routines"},
     {ERR_PACK(ERR_LIB_CT, 0, 0), "CT routines"},
     {ERR_PACK(ERR_LIB_ASYNC, 0, 0), "ASYNC routines"},
+    {ERR_PACK(ERR_LIB_KDF, 0, 0), "KDF routines"},
     {ERR_PACK(ERR_LIB_OSSL_STORE, 0, 0), "STORE routines"},
     {ERR_PACK(ERR_LIB_SM2, 0, 0), "SM2 routines"},
     {ERR_PACK(ERR_LIB_ESS, 0, 0), "ESS routines"},
     {ERR_PACK(ERR_LIB_PROV, 0, 0), "Provider routines"},
+    {ERR_PACK(ERR_LIB_OSSL_ENCODER, 0, 0), "ENCODER routines"},
+    {ERR_PACK(ERR_LIB_OSSL_DECODER, 0, 0), "DECODER routines"},
+    {ERR_PACK(ERR_LIB_HTTP, 0, 0), "HTTP routines"},
     {0, NULL},
 };
 
@@ -110,7 +113,20 @@ static ERR_STRING_DATA ERR_str_reasons[] = {
     {ERR_R_DISABLED, "called a function that was disabled at compile-time"},
     {ERR_R_INIT_FAIL, "init fail"},
     {ERR_R_OPERATION_FAIL, "operation fail"},
+    {ERR_R_INVALID_PROVIDER_FUNCTIONS, "invalid provider functions"},
+    {ERR_R_INTERRUPTED_OR_CANCELLED, "interrupted or cancelled"},
 
+    /*
+     * Something is unsupported, exactly what is expressed with additional data
+     */
+    {ERR_R_UNSUPPORTED, "unsupported"},
+    /*
+     * A fetch failed for other reasons than the name to be fetched being
+     * unsupported.
+     */
+    {ERR_R_FETCH_FAILED, "fetch failed"},
+
+    {ERR_R_INVALID_PROPERTY_DEFINITION, "invalid property definition"},
     {0, NULL},
 };
 #endif
@@ -161,91 +177,14 @@ static ERR_STRING_DATA *int_err_get_item(const ERR_STRING_DATA *d)
 {
     ERR_STRING_DATA *p = NULL;
 
-    CRYPTO_THREAD_read_lock(err_string_lock);
+    if (!CRYPTO_THREAD_read_lock(err_string_lock))
+        return NULL;
     p = lh_ERR_STRING_DATA_retrieve(int_error_hash, d);
     CRYPTO_THREAD_unlock(err_string_lock);
 
     return p;
 }
 
-#ifndef OPENSSL_NO_ERR
-/* 2019-05-21: Russian and Ukrainian locales on Linux require more than 6,5 kB */
-# define SPACE_SYS_STR_REASONS 8 * 1024
-# define NUM_SYS_STR_REASONS 127
-
-static ERR_STRING_DATA SYS_str_reasons[NUM_SYS_STR_REASONS + 1];
-/*
- * SYS_str_reasons is filled with copies of strerror() results at
- * initialization. 'errno' values up to 127 should cover all usual errors,
- * others will be displayed numerically by ERR_error_string. It is crucial
- * that we have something for each reason code that occurs in
- * ERR_str_reasons, or bogus reason strings will be returned for SYSerr(),
- * which always gets an errno value and never one of those 'standard' reason
- * codes.
- */
-
-static void build_SYS_str_reasons(void)
-{
-    /* OPENSSL_malloc cannot be used here, use static storage instead */
-    static char strerror_pool[SPACE_SYS_STR_REASONS];
-    char *cur = strerror_pool;
-    size_t cnt = 0;
-    static int init = 1;
-    int i;
-    int saveerrno = get_last_sys_error();
-
-    CRYPTO_THREAD_write_lock(err_string_lock);
-    if (!init) {
-        CRYPTO_THREAD_unlock(err_string_lock);
-        return;
-    }
-
-    for (i = 1; i <= NUM_SYS_STR_REASONS; i++) {
-        ERR_STRING_DATA *str = &SYS_str_reasons[i - 1];
-
-        str->error = ERR_PACK(ERR_LIB_SYS, 0, i);
-        /*
-         * If we have used up all the space in strerror_pool,
-         * there's no point in calling openssl_strerror_r()
-         */
-        if (str->string == NULL && cnt < sizeof(strerror_pool)) {
-            if (openssl_strerror_r(i, cur, sizeof(strerror_pool) - cnt)) {
-                size_t l = strlen(cur);
-
-                str->string = cur;
-                cnt += l;
-                cur += l;
-
-                /*
-                 * VMS has an unusual quirk of adding spaces at the end of
-                 * some (most? all?) messages. Lets trim them off.
-                 */
-                while (cur > strerror_pool && ossl_isspace(cur[-1])) {
-                    cur--;
-                    cnt--;
-                }
-                *cur++ = '\0';
-                cnt++;
-            }
-        }
-        if (str->string == NULL)
-            str->string = "unknown";
-    }
-
-    /*
-     * Now we still have SYS_str_reasons[NUM_SYS_STR_REASONS] = {0, NULL}, as
-     * required by ERR_load_strings.
-     */
-
-    init = 0;
-
-    CRYPTO_THREAD_unlock(err_string_lock);
-    /* openssl_strerror_r could change errno, but we want to preserve it */
-    set_sys_error(saveerrno);
-    err_load_strings(SYS_str_reasons);
-}
-#endif
-
 static void ERR_STATE_free(ERR_STATE *s)
 {
     int i;
@@ -253,14 +192,14 @@ static void ERR_STATE_free(ERR_STATE *s)
     if (s == NULL)
         return;
     for (i = 0; i < ERR_NUM_ERRORS; i++) {
-        err_clear_data(s, i, 1);
+        err_clear(s, i, 1);
     }
     OPENSSL_free(s);
 }
 
 DEFINE_RUN_ONCE_STATIC(do_err_strings_init)
 {
-    if (!OPENSSL_init_crypto(0, NULL))
+    if (!OPENSSL_init_crypto(OPENSSL_INIT_BASE_ONLY, NULL))
         return 0;
     err_string_lock = CRYPTO_THREAD_lock_new();
     if (err_string_lock == NULL)
@@ -297,11 +236,12 @@ static void err_patch(int lib, ERR_STRING_DATA *str)
 }
 
 /*
- * Hash in |str| error strings. Assumes the URN_ONCE was done.
+ * Hash in |str| error strings. Assumes the RUN_ONCE was done.
  */
 static int err_load_strings(const ERR_STRING_DATA *str)
 {
-    CRYPTO_THREAD_write_lock(err_string_lock);
+    if (!CRYPTO_THREAD_write_lock(err_string_lock))
+        return 0;
     for (; str->error; str++)
         (void)lh_ERR_STRING_DATA_insert(int_error_hash,
                                        (ERR_STRING_DATA *)str);
@@ -309,7 +249,7 @@ static int err_load_strings(const ERR_STRING_DATA *str)
     return 1;
 }
 
-int ERR_load_ERR_strings(void)
+int ossl_err_load_ERR_strings(void)
 {
 #ifndef OPENSSL_NO_ERR
     if (!RUN_ONCE(&err_string_init, do_err_strings_init))
@@ -317,14 +257,13 @@ int ERR_load_ERR_strings(void)
 
     err_load_strings(ERR_str_libraries);
     err_load_strings(ERR_str_reasons);
-    build_SYS_str_reasons();
 #endif
     return 1;
 }
 
 int ERR_load_strings(int lib, ERR_STRING_DATA *str)
 {
-    if (ERR_load_ERR_strings() == 0)
+    if (ossl_err_load_ERR_strings() == 0)
         return 0;
 
     err_patch(lib, str);
@@ -334,7 +273,7 @@ int ERR_load_strings(int lib, ERR_STRING_DATA *str)
 
 int ERR_load_strings_const(const ERR_STRING_DATA *str)
 {
-    if (ERR_load_ERR_strings() == 0)
+    if (ossl_err_load_ERR_strings() == 0)
         return 0;
     err_load_strings(str);
     return 1;
@@ -345,7 +284,8 @@ int ERR_unload_strings(int lib, ERR_STRING_DATA *str)
     if (!RUN_ONCE(&err_string_init, do_err_strings_init))
         return 0;
 
-    CRYPTO_THREAD_write_lock(err_string_lock);
+    if (!CRYPTO_THREAD_write_lock(err_string_lock))
+        return 0;
     /*
      * We don't need to ERR_PACK the lib, since that was done (to
      * the table) when it was loaded.
@@ -370,7 +310,7 @@ void ERR_clear_error(void)
     int i;
     ERR_STATE *es;
 
-    es = err_get_state_int();
+    es = ossl_err_get_state_int();
     if (es == NULL)
         return;
 
@@ -385,21 +325,6 @@ unsigned long ERR_get_error(void)
     return get_error_values(EV_POP, NULL, NULL, NULL, NULL, NULL);
 }
 
-unsigned long ERR_get_error_line(const char **file, int *line)
-{
-    return get_error_values(EV_POP, file, line, NULL, NULL, NULL);
-}
-
-unsigned long ERR_get_error_func(const char **func)
-{
-    return get_error_values(EV_POP, NULL, NULL, func, NULL, NULL);
-}
-
-unsigned long ERR_get_error_data(const char **data, int *flags)
-{
-    return get_error_values(EV_POP, NULL, NULL, NULL, data, flags);
-}
-
 unsigned long ERR_get_error_all(const char **file, int *line,
                                 const char **func,
                                 const char **data, int *flags)
@@ -407,7 +332,12 @@ unsigned long ERR_get_error_all(const char **file, int *line,
     return get_error_values(EV_POP, file, line, func, data, flags);
 }
 
-#if !OPENSSL_API_3
+#ifndef OPENSSL_NO_DEPRECATED_3_0
+unsigned long ERR_get_error_line(const char **file, int *line)
+{
+    return get_error_values(EV_POP, file, line, NULL, NULL, NULL);
+}
+
 unsigned long ERR_get_error_line_data(const char **file, int *line,
                                       const char **data, int *flags)
 {
@@ -442,7 +372,7 @@ unsigned long ERR_peek_error_all(const char **file, int *line,
     return get_error_values(EV_PEEK, file, line, func, data, flags);
 }
 
-#if !OPENSSL_API_3
+#ifndef OPENSSL_NO_DEPRECATED_3_0
 unsigned long ERR_peek_error_line_data(const char **file, int *line,
                                        const char **data, int *flags)
 {
@@ -477,7 +407,7 @@ unsigned long ERR_peek_last_error_all(const char **file, int *line,
     return get_error_values(EV_PEEK_LAST, file, line, func, data, flags);
 }
 
-#if !OPENSSL_API_3
+#ifndef OPENSSL_NO_DEPRECATED_3_0
 unsigned long ERR_peek_last_error_line_data(const char **file, int *line,
                                             const char **data, int *flags)
 {
@@ -494,7 +424,7 @@ static unsigned long get_error_values(ERR_GET_ACTION g,
     ERR_STATE *es;
     unsigned long ret;
 
-    es = err_get_state_int();
+    es = ossl_err_get_state_int();
     if (es == NULL)
         return 0;
 
@@ -533,45 +463,41 @@ static unsigned long get_error_values(ERR_GET_ACTION g,
         es->err_buffer[i] = 0;
     }
 
-    if (file != NULL && line != NULL) {
-        if (es->err_file[i] == NULL) {
-            *file = "NA";
-            *line = 0;
-        } else {
-            *file = es->err_file[i];
-            *line = es->err_line[i];
-        }
+    if (file != NULL) {
+        *file = es->err_file[i];
+        if (*file == NULL)
+            *file = "";
     }
-
+    if (line != NULL)
+        *line = es->err_line[i];
     if (func != NULL) {
         *func = es->err_func[i];
         if (*func == NULL)
-            *func = "N/A";
+            *func = "";
     }
-
+    if (flags != NULL)
+        *flags = es->err_data_flags[i];
     if (data == NULL) {
         if (g == EV_POP) {
             err_clear_data(es, i, 0);
         }
     } else {
-        if (es->err_data[i] == NULL) {
+        *data = es->err_data[i];
+        if (*data == NULL) {
             *data = "";
             if (flags != NULL)
                 *flags = 0;
-        } else {
-            *data = es->err_data[i];
-            if (flags != NULL)
-                *flags = es->err_data_flags[i];
         }
     }
     return ret;
 }
 
-void ERR_error_string_n(unsigned long e, char *buf, size_t len)
+void ossl_err_string_int(unsigned long e, const char *func,
+                         char *buf, size_t len)
 {
-    char lsbuf[64], rsbuf[64];
-    const char *ls, *rs;
-    unsigned long f = 0, l, r;
+    char lsbuf[64], rsbuf[256];
+    const char *ls, *rs = NULL;
+    unsigned long l, r;
 
     if (len == 0)
         return;
@@ -583,20 +509,39 @@ void ERR_error_string_n(unsigned long e, char *buf, size_t len)
         ls = lsbuf;
     }
 
-    rs = ERR_reason_error_string(e);
+    /*
+     * ERR_reason_error_string() can't safely return system error strings,
+     * since it would call openssl_strerror_r(), which needs a buffer for
+     * thread safety.  So for system errors, we call openssl_strerror_r()
+     * directly instead.
+     */
     r = ERR_GET_REASON(e);
+#ifndef OPENSSL_NO_ERR
+    if (ERR_SYSTEM_ERROR(e)) {
+        if (openssl_strerror_r(r, rsbuf, sizeof(rsbuf)))
+            rs = rsbuf;
+    } else {
+        rs = ERR_reason_error_string(e);
+    }
+#endif
     if (rs == NULL) {
         BIO_snprintf(rsbuf, sizeof(rsbuf), "reason(%lu)", r);
         rs = rsbuf;
     }
 
-    BIO_snprintf(buf, len, "error:%08lX:%s:%s:%s", e, ls, "", rs);
+    BIO_snprintf(buf, len, "error:%08lX:%s:%s:%s", e, ls, func, rs);
     if (strlen(buf) == len - 1) {
         /* Didn't fit; use a minimal format. */
-        BIO_snprintf(buf, len, "err:%lx:%lx:%lx:%lx", e, l, f, r);
+        BIO_snprintf(buf, len, "err:%lx:%lx:%lx:%lx", e, l, 0L, r);
     }
 }
 
+
+void ERR_error_string_n(unsigned long e, char *buf, size_t len)
+{
+    ossl_err_string_int(e, "", buf, len);
+}
+
 /*
  * ERR_error_string_n should be used instead for ret != NULL as
  * ERR_error_string cannot know how large the buffer is
@@ -626,7 +571,7 @@ const char *ERR_lib_error_string(unsigned long e)
     return ((p == NULL) ? NULL : p->string);
 }
 
-#if !OPENSSL_API_3
+#ifndef OPENSSL_NO_DEPRECATED_3_0
 const char *ERR_func_error_string(unsigned long e)
 {
     return NULL;
@@ -642,19 +587,26 @@ const char *ERR_reason_error_string(unsigned long e)
         return NULL;
     }
 
+    /*
+     * ERR_reason_error_string() can't safely return system error strings,
+     * since openssl_strerror_r() needs a buffer for thread safety, and we
+     * haven't got one that would serve any sensible purpose.
+     */
+    if (ERR_SYSTEM_ERROR(e))
+        return NULL;
+
     l = ERR_GET_LIB(e);
     r = ERR_GET_REASON(e);
     d.error = ERR_PACK(l, 0, r);
     p = int_err_get_item(&d);
-    if (!p) {
+    if (p == NULL) {
         d.error = ERR_PACK(0, 0, r);
         p = int_err_get_item(&d);
     }
     return ((p == NULL) ? NULL : p->string);
 }
 
-/* TODO(3.0): arg ignored for now */
-static void err_delete_thread_state(void *arg)
+static void err_delete_thread_state(void *unused)
 {
     ERR_STATE *state = CRYPTO_THREAD_get_local(&err_thread_local);
     if (state == NULL)
@@ -664,13 +616,13 @@ static void err_delete_thread_state(void *arg)
     ERR_STATE_free(state);
 }
 
-#if !OPENSSL_API_1_1_0
+#ifndef OPENSSL_NO_DEPRECATED_1_1_0
 void ERR_remove_thread_state(void *dummy)
 {
 }
 #endif
 
-#if !OPENSSL_API_1_0_0
+#ifndef OPENSSL_NO_DEPRECATED_1_0_0
 void ERR_remove_state(unsigned long pid)
 {
 }
@@ -682,7 +634,7 @@ DEFINE_RUN_ONCE_STATIC(err_do_init)
     return CRYPTO_THREAD_init_local(&err_thread_local, NULL);
 }
 
-ERR_STATE *err_get_state_int(void)
+ERR_STATE *ossl_err_get_state_int(void)
 {
     ERR_STATE *state;
     int saveerrno = get_last_sys_error();
@@ -721,10 +673,10 @@ ERR_STATE *err_get_state_int(void)
     return state;
 }
 
-#if !OPENSSL_API_3
+#ifndef OPENSSL_NO_DEPRECATED_3_0
 ERR_STATE *ERR_get_state(void)
 {
-    return err_get_state_int();
+    return ossl_err_get_state_int();
 }
 #endif
 
@@ -780,7 +732,8 @@ int ERR_get_next_error_library(void)
     if (!RUN_ONCE(&err_string_init, do_err_strings_init))
         return 0;
 
-    CRYPTO_THREAD_write_lock(err_string_lock);
+    if (!CRYPTO_THREAD_write_lock(err_string_lock))
+        return 0;
     ret = int_err_library_number++;
     CRYPTO_THREAD_unlock(err_string_lock);
     return ret;
@@ -791,7 +744,7 @@ static int err_set_error_data_int(char *data, size_t size, int flags,
 {
     ERR_STATE *es;
 
-    es = err_get_state_int();
+    es = ossl_err_get_state_int();
     if (es == NULL)
         return 0;
 
@@ -836,7 +789,7 @@ void ERR_add_error_vdata(int num, va_list args)
     ERR_STATE *es;
 
     /* Get the current error data; if an allocated string get it. */
-    es = err_get_state_int();
+    es = ossl_err_get_state_int();
     if (es == NULL)
         return;
     i = es->top;
@@ -891,13 +844,13 @@ int ERR_set_mark(void)
 {
     ERR_STATE *es;
 
-    es = err_get_state_int();
+    es = ossl_err_get_state_int();
     if (es == NULL)
         return 0;
 
     if (es->bottom == es->top)
         return 0;
-    es->err_flags[es->top] |= ERR_FLAG_MARK;
+    es->err_marks[es->top]++;
     return 1;
 }
 
@@ -905,19 +858,19 @@ int ERR_pop_to_mark(void)
 {
     ERR_STATE *es;
 
-    es = err_get_state_int();
+    es = ossl_err_get_state_int();
     if (es == NULL)
         return 0;
 
     while (es->bottom != es->top
-           && (es->err_flags[es->top] & ERR_FLAG_MARK) == 0) {
+           && es->err_marks[es->top] == 0) {
         err_clear(es, es->top, 0);
         es->top = es->top > 0 ? es->top - 1 : ERR_NUM_ERRORS - 1;
     }
 
     if (es->bottom == es->top)
         return 0;
-    es->err_flags[es->top] &= ~ERR_FLAG_MARK;
+    es->err_marks[es->top]--;
     return 1;
 }
 
@@ -926,19 +879,19 @@ int ERR_clear_last_mark(void)
     ERR_STATE *es;
     int top;
 
-    es = err_get_state_int();
+    es = ossl_err_get_state_int();
     if (es == NULL)
         return 0;
 
     top = es->top;
     while (es->bottom != top
-           && (es->err_flags[top] & ERR_FLAG_MARK) == 0) {
+           && es->err_marks[top] == 0) {
         top = top > 0 ? top - 1 : ERR_NUM_ERRORS - 1;
     }
 
     if (es->bottom == top)
         return 0;
-    es->err_flags[top] &= ~ERR_FLAG_MARK;
+    es->err_marks[top]--;
     return 1;
 }
 
@@ -947,7 +900,7 @@ void err_clear_last_constant_time(int clear)
     ERR_STATE *es;
     int top;
 
-    es = err_get_state_int();
+    es = ossl_err_get_state_int();
     if (es == NULL)
         return;