xref: /freebsd/crypto/openssl/test/x509_req_test.c (revision dece5b05f577fc4c6b89af7ad48dfbdf7cc4945c)
1 /*
2  * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9 
10 #include <openssl/core_names.h>
11 #include <openssl/pem.h>
12 #include <openssl/x509.h>
13 #include <openssl/x509v3.h>
14 
15 #include "testutil.h"
16 
17 static char *certsDir = NULL;
18 
19 /*
20  * Test for the missing X509 version check discussed in issue #5738 and
21  * added in PR #24677.
22  * This test tries to verify a malformed CSR with the X509 version set
23  * version 6, instead of 1. As this request is malformed, even its
24  * signature is valid, the verification must fail.
25  */
26 static int test_x509_req_detect_invalid_version(void)
27 {
28     char *certFilePath;
29     BIO *bio = NULL;
30     EVP_PKEY *pkey = NULL;
31     X509_REQ *req = NULL;
32     int ret = 0;
33 
34     certFilePath = test_mk_file_path(certsDir, "x509-req-detect-invalid-version.pem");
35     if (certFilePath == NULL)
36         goto err;
37     if (!TEST_ptr(bio = BIO_new_file(certFilePath, "r")))
38         goto err;
39     req = PEM_read_bio_X509_REQ(bio, NULL, 0, NULL);
40     if (req == NULL) {
41         ret = 1; /* success, reading PEM with invalid CSR data is allowed to fail. */
42         goto err;
43     }
44     if (!TEST_ptr(pkey = X509_REQ_get_pubkey(req)))
45         goto err;
46     /* Verification MUST fail at this point. ret != 1. */
47     if (!TEST_int_ne(X509_REQ_verify(req, pkey), 1))
48         goto err;
49     ret = 1; /* success */
50 err:
51     EVP_PKEY_free(pkey);
52     X509_REQ_free(req);
53     BIO_free(bio);
54     OPENSSL_free(certFilePath);
55     return ret;
56 }
57 
58 static int add_ext(STACK_OF(X509_EXTENSION) *sk, int nid, char *value)
59 {
60     X509_EXTENSION *ex;
61     ex = X509V3_EXT_conf_nid(NULL, NULL, nid, value);
62     if (!ex)
63         return 0;
64     if (sk_X509_EXTENSION_push(sk, ex) <= 0) {
65         X509_EXTENSION_free(ex);
66         return 0;
67     }
68 
69     return 1;
70 }
71 
72 static int test_x509_req_add_exts(void)
73 {
74     X509_REQ *x = NULL;
75     STACK_OF(X509_EXTENSION) *exts = NULL;
76     EVP_PKEY_CTX *ctx = NULL;
77     EVP_PKEY *pkey = NULL;
78     int ret = 0;
79     int nid = NID_undef;
80     OSSL_PARAM params[2];
81     size_t bits = 2048;
82 
83     params[0] = OSSL_PARAM_construct_size_t(OSSL_PKEY_PARAM_RSA_BITS, &bits);
84     params[1] = OSSL_PARAM_construct_end();
85 
86     ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
87     if (ctx == NULL
88         || EVP_PKEY_keygen_init(ctx) <= 0
89         || EVP_PKEY_CTX_set_params(ctx, params) <= 0
90         || EVP_PKEY_keygen(ctx, &pkey) <= 0
91         || (x = X509_REQ_new()) == NULL
92         || X509_REQ_set_pubkey(x, pkey) <= 0)
93         goto err;
94 
95     exts = sk_X509_EXTENSION_new_null();
96     if (!TEST_ptr(exts))
97         goto err;
98 
99     /*
100      * For request extensions they are all packed in a single attribute. We
101      * save them in a STACK and add them all at once later...
102      */
103 
104     if (!TEST_int_eq(add_ext(exts, NID_netscape_cert_type, "client,email"), 1)
105         || !TEST_int_eq(add_ext(exts, NID_subject_alt_name, "email:steve@openssl.org"), 1)
106         || !TEST_int_eq(add_ext(exts, NID_crl_distribution_points, "URI:http://example.org"), 1)
107         /* These tests require some underlying config but we just check that we don't crash */
108         || !TEST_int_eq(add_ext(exts, NID_proxyCertInfo, "text:xxx"), 0)
109         || !TEST_int_eq(add_ext(exts, NID_certificate_policies, "xxx:yyy"), 0)
110         /* Some Netscape specific extensions */
111         || !TEST_int_eq(add_ext(exts, NID_netscape_cert_type, "client,email"), 1))
112         goto err;
113 
114     /* Maybe even add our own extension based on existing */
115     nid = OBJ_create("1.2.3.4", "MyAlias", "My Test Alias Extension");
116     if (!TEST_int_ne(nid, NID_undef)
117         || !TEST_int_gt(X509V3_EXT_add_alias(nid, NID_netscape_comment), 0)
118         || !TEST_int_eq(add_ext(exts, nid, "example comment alias"), 1)
119         || !TEST_int_eq(X509_REQ_add_extensions(x, exts), 1))
120         goto err;
121 
122     if (!X509_REQ_sign(x, pkey, EVP_sha256()))
123         goto err;
124 
125     ret = 1;
126 err:
127     EVP_PKEY_CTX_free(ctx);
128 
129     X509_REQ_free(x);
130     EVP_PKEY_free(pkey);
131     sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
132 
133     return ret;
134 }
135 OPT_TEST_DECLARE_USAGE("certdir\n")
136 
137 int setup_tests(void)
138 {
139     if (!test_skip_common_options()) {
140         TEST_error("Error parsing test options\n");
141         return 0;
142     }
143     if (!TEST_ptr(certsDir = test_get_argument(0)))
144         return 0;
145 
146     ADD_TEST(test_x509_req_detect_invalid_version);
147     ADD_TEST(test_x509_req_add_exts);
148     return 1;
149 }
150 
151 void cleanup_tests(void)
152 {
153 }
154