xref: /openbsd-src/lib/libcrypto/x509/x509_siginfo.c (revision c5d7bed5dd774f32fe3ef5eeee814d3acfe35920)
1 /*	$OpenBSD: x509_siginfo.c,v 1.1 2024/08/28 07:15:04 tb Exp $ */
2 
3 /*
4  * Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <openssl/evp.h>
20 #include <openssl/objects.h>
21 #include <openssl/x509.h>
22 
23 #include "evp_local.h"
24 
25 #include "x509_internal.h"
26 
27 static int
28 x509_find_sigid_algs(const X509 *x509, int *out_md_nid, int *out_pkey_nid)
29 {
30 	const ASN1_OBJECT *aobj;
31 	int nid;
32 
33 	*out_md_nid = NID_undef;
34 	*out_pkey_nid = NID_undef;
35 
36 	X509_ALGOR_get0(&aobj, NULL, NULL, x509->sig_alg);
37 	if ((nid = OBJ_obj2nid(aobj)) == NID_undef)
38 		return 0;
39 
40 	return OBJ_find_sigid_algs(nid, out_md_nid, out_pkey_nid);
41 }
42 
43 int
44 X509_get_signature_info(X509 *x509, int *out_md_nid, int *out_pkey_nid,
45     int *out_security_bits, uint32_t *out_flags)
46 {
47 	const EVP_MD *md;
48 	int md_nid = NID_undef, pkey_nid = NID_undef, security_bits = -1;
49 	uint32_t flags = 0;
50 
51 	if (out_md_nid != NULL)
52 		*out_md_nid = md_nid;
53 	if (out_pkey_nid != NULL)
54 		*out_pkey_nid = pkey_nid;
55 	if (out_security_bits != NULL)
56 		*out_security_bits = security_bits;
57 	if (out_flags != NULL)
58 		*out_flags = flags;
59 
60 	if (!x509v3_cache_extensions(x509))
61 		goto err;
62 
63 	if (!x509_find_sigid_algs(x509, &md_nid, &pkey_nid))
64 		goto err;
65 
66 	/*
67 	 * If md_nid == NID_undef, this means we need to consult the ameth.
68 	 * Handlers are available for EdDSA and RSA-PSS. No other signature
69 	 * algorithm with NID_undef should appear in a certificate.
70 	 */
71 	if (md_nid == NID_undef) {
72 		const EVP_PKEY_ASN1_METHOD *ameth;
73 
74 		if ((ameth = EVP_PKEY_asn1_find(NULL, pkey_nid)) == NULL ||
75 		    ameth->signature_info == NULL)
76 			goto err;
77 
78 		if (!ameth->signature_info(x509->sig_alg, &md_nid, &pkey_nid,
79 		    &security_bits, &flags))
80 			goto err;
81 
82 		goto done;
83 	}
84 
85 	/* XXX - OpenSSL 3 special cases SHA-1 (63 bits) and MD5 (39 bits). */
86 	if ((md = EVP_get_digestbynid(md_nid)) == NULL)
87 		goto err;
88 
89 	/* Assume 4 bits of collision resistance per octet. */
90 	if ((security_bits = EVP_MD_size(md)) <= 0)
91 		goto err;
92 	security_bits *= 4;
93 
94 	if (md_nid == NID_sha1 || md_nid == NID_sha256 ||
95 	    md_nid == NID_sha384 || md_nid == NID_sha512)
96 		flags |= X509_SIG_INFO_TLS;
97 
98 	flags |= X509_SIG_INFO_VALID;
99 
100  done:
101 	if (out_md_nid != NULL)
102 		*out_md_nid = md_nid;
103 	if (out_pkey_nid != NULL)
104 		*out_pkey_nid = pkey_nid;
105 	if (out_security_bits != NULL)
106 		*out_security_bits = security_bits;
107 	if (out_flags != NULL)
108 		*out_flags = flags;
109 
110  err:
111 	return (flags & X509_SIG_INFO_VALID) != 0;
112 }
113 LCRYPTO_ALIAS(X509_get_signature_info);
114