Prevent crash in X509_NAME_cmp() etc. when cert has no issuer or no serialNumber
[openssl.git] / crypto / self_test_core.c
index 77864a230be66e85da0fd3ac0f89e07b51787ef9..bee3161ed5e8054927032eee902b333805791548 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2019-2020 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
@@ -8,6 +8,8 @@
  */
 
 #include <openssl/self_test.h>
+#include <openssl/core_names.h>
+#include <openssl/params.h>
 #include "internal/cryptlib.h"
 
 typedef struct self_test_cb_st
@@ -16,6 +18,19 @@ typedef struct self_test_cb_st
     void *cbarg;
 } SELF_TEST_CB;
 
+struct ossl_self_test_st
+{
+    /* local state variables */
+    const char *phase;
+    const char *type;
+    const char *desc;
+    OSSL_CALLBACK *cb;
+
+    /* callback related variables used to pass the state back to the user */
+    OSSL_PARAM params[4];
+    void *cb_arg;
+};
+
 static void *self_test_set_callback_new(OPENSSL_CTX *ctx)
 {
     SELF_TEST_CB *stcb;
@@ -40,6 +55,7 @@ static SELF_TEST_CB *get_self_test_callback(OPENSSL_CTX *libctx)
                                 &self_test_set_callback_method);
 }
 
+#ifndef FIPS_MODE
 void OSSL_SELF_TEST_set_callback(OPENSSL_CTX *libctx, OSSL_CALLBACK *cb,
                                  void *cbarg)
 {
@@ -50,6 +66,8 @@ void OSSL_SELF_TEST_set_callback(OPENSSL_CTX *libctx, OSSL_CALLBACK *cb,
         stcb->cbarg = cbarg;
     }
 }
+#endif /* FIPS_MODE */
+
 void OSSL_SELF_TEST_get_callback(OPENSSL_CTX *libctx, OSSL_CALLBACK **cb,
                                  void **cbarg)
 {
@@ -60,3 +78,91 @@ void OSSL_SELF_TEST_get_callback(OPENSSL_CTX *libctx, OSSL_CALLBACK **cb,
     if (cbarg != NULL)
         *cbarg = (stcb != NULL ? stcb->cbarg : NULL);
 }
+
+static void self_test_setparams(OSSL_SELF_TEST *st)
+{
+    size_t n = 0;
+
+    if (st->cb != NULL) {
+        st->params[n++] =
+            OSSL_PARAM_construct_utf8_string(OSSL_PROV_PARAM_SELF_TEST_PHASE,
+                                             (char *)st->phase, 0);
+        st->params[n++] =
+            OSSL_PARAM_construct_utf8_string(OSSL_PROV_PARAM_SELF_TEST_TYPE,
+                                             (char *)st->type, 0);
+        st->params[n++] =
+            OSSL_PARAM_construct_utf8_string(OSSL_PROV_PARAM_SELF_TEST_DESC,
+                                             (char *)st->desc, 0);
+    }
+    st->params[n++] = OSSL_PARAM_construct_end();
+}
+
+OSSL_SELF_TEST *OSSL_SELF_TEST_new(OSSL_CALLBACK *cb, void *cbarg)
+{
+    OSSL_SELF_TEST *ret = OPENSSL_zalloc(sizeof(*ret));
+
+    if (ret == NULL)
+        return NULL;
+
+    ret->cb = cb;
+    ret->cb_arg = cbarg;
+    ret->phase = "";
+    ret->type = "";
+    ret->desc = "";
+    self_test_setparams(ret);
+    return ret;
+}
+
+void OSSL_SELF_TEST_free(OSSL_SELF_TEST *st)
+{
+    OPENSSL_free(st);
+}
+
+/* Can be used during application testing to log that a test has started. */
+void OSSL_SELF_TEST_onbegin(OSSL_SELF_TEST *st, const char *type,
+                            const char *desc)
+{
+    if (st != NULL && st->cb != NULL) {
+        st->phase = OSSL_SELF_TEST_PHASE_START;
+        st->type = type;
+        st->desc = desc;
+        self_test_setparams(st);
+        (void)st->cb(st->params, st->cb_arg);
+    }
+}
+
+/*
+ * Can be used during application testing to log that a test has either
+ * passed or failed.
+ */
+void OSSL_SELF_TEST_onend(OSSL_SELF_TEST *st, int ret)
+{
+    if (st != NULL && st->cb != NULL) {
+        st->phase =
+            (ret == 1 ? OSSL_SELF_TEST_PHASE_PASS : OSSL_SELF_TEST_PHASE_FAIL);
+        self_test_setparams(st);
+        (void)st->cb(st->params, st->cb_arg);
+
+        st->phase = OSSL_SELF_TEST_PHASE_NONE;
+        st->type = OSSL_SELF_TEST_TYPE_NONE;
+        st->desc = OSSL_SELF_TEST_DESC_NONE;
+    }
+}
+
+/*
+ * Used for failure testing.
+ *
+ * Call the applications SELF_TEST_cb() if it exists.
+ * If the application callback decides to return 0 then the first byte of 'bytes'
+ * is modified (corrupted). This is used to modify output signatures or
+ * ciphertext before they are verified or decrypted.
+ */
+void OSSL_SELF_TEST_oncorrupt_byte(OSSL_SELF_TEST *st, unsigned char *bytes)
+{
+    if (st != NULL && st->cb != NULL) {
+        st->phase = OSSL_SELF_TEST_PHASE_CORRUPT;
+        self_test_setparams(st);
+        if (!st->cb(st->params, st->cb_arg))
+            bytes[0] ^= 1;
+    }
+}