xref: /openbsd-src/lib/libcrypto/ocsp/ocsp_lib.c (revision de5c7f0b99056f22483141bcdfd727809ea02ae1)
1*de5c7f0bStb /* $OpenBSD: ocsp_lib.c,v 1.28 2024/08/28 06:27:19 tb Exp $ */
2da347917Sbeck /* Written by Tom Titchener <Tom_Titchener@groove.net> for the OpenSSL
3da347917Sbeck  * project. */
4da347917Sbeck 
5da347917Sbeck /* History:
6da347917Sbeck    This file was transfered to Richard Levitte from CertCo by Kathy
7da347917Sbeck    Weinhold in mid-spring 2000 to be included in OpenSSL or released
8da347917Sbeck    as a patch kit. */
9da347917Sbeck 
10da347917Sbeck /* ====================================================================
11da347917Sbeck  * Copyright (c) 1998-2000 The OpenSSL Project.  All rights reserved.
12da347917Sbeck  *
13da347917Sbeck  * Redistribution and use in source and binary forms, with or without
14da347917Sbeck  * modification, are permitted provided that the following conditions
15da347917Sbeck  * are met:
16da347917Sbeck  *
17da347917Sbeck  * 1. Redistributions of source code must retain the above copyright
18da347917Sbeck  *    notice, this list of conditions and the following disclaimer.
19da347917Sbeck  *
20da347917Sbeck  * 2. Redistributions in binary form must reproduce the above copyright
21da347917Sbeck  *    notice, this list of conditions and the following disclaimer in
22da347917Sbeck  *    the documentation and/or other materials provided with the
23da347917Sbeck  *    distribution.
24da347917Sbeck  *
25da347917Sbeck  * 3. All advertising materials mentioning features or use of this
26da347917Sbeck  *    software must display the following acknowledgment:
27da347917Sbeck  *    "This product includes software developed by the OpenSSL Project
28da347917Sbeck  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
29da347917Sbeck  *
30da347917Sbeck  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
31da347917Sbeck  *    endorse or promote products derived from this software without
32da347917Sbeck  *    prior written permission. For written permission, please contact
33da347917Sbeck  *    openssl-core@openssl.org.
34da347917Sbeck  *
35da347917Sbeck  * 5. Products derived from this software may not be called "OpenSSL"
36da347917Sbeck  *    nor may "OpenSSL" appear in their names without prior written
37da347917Sbeck  *    permission of the OpenSSL Project.
38da347917Sbeck  *
39da347917Sbeck  * 6. Redistributions of any form whatsoever must retain the following
40da347917Sbeck  *    acknowledgment:
41da347917Sbeck  *    "This product includes software developed by the OpenSSL Project
42da347917Sbeck  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
43da347917Sbeck  *
44da347917Sbeck  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
45da347917Sbeck  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46da347917Sbeck  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
47da347917Sbeck  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
48da347917Sbeck  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
49da347917Sbeck  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
50da347917Sbeck  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
51da347917Sbeck  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52da347917Sbeck  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
53da347917Sbeck  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
54da347917Sbeck  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
55da347917Sbeck  * OF THE POSSIBILITY OF SUCH DAMAGE.
56da347917Sbeck  * ====================================================================
57da347917Sbeck  *
58da347917Sbeck  * This product includes cryptographic software written by Eric Young
59da347917Sbeck  * (eay@cryptsoft.com).  This product includes software written by Tim
60da347917Sbeck  * Hudson (tjh@cryptsoft.com).
61da347917Sbeck  *
62da347917Sbeck  */
63da347917Sbeck 
64a8913c44Sjsing #include <stdio.h>
65a8913c44Sjsing #include <string.h>
66a8913c44Sjsing 
678cf4d6a6Sjsing #include <openssl/opensslconf.h>
688cf4d6a6Sjsing 
69b6ab114eSjsing #include <openssl/asn1t.h>
70b6ab114eSjsing #include <openssl/err.h>
71da347917Sbeck #include <openssl/objects.h>
72b6ab114eSjsing #include <openssl/ocsp.h>
73b6ab114eSjsing #include <openssl/pem.h>
74da347917Sbeck #include <openssl/x509.h>
75da347917Sbeck #include <openssl/x509v3.h>
76da347917Sbeck 
779f44a700Stb #include "ocsp_local.h"
78a3eeb048Stb #include "x509_local.h"
799f44a700Stb 
80da347917Sbeck /* Convert a certificate and its issuer to an OCSP_CERTID */
81da347917Sbeck 
822d2941d0Smiod OCSP_CERTID *
839a659387Stb OCSP_cert_to_id(const EVP_MD *dgst, const X509 *subject, const X509 *issuer)
84da347917Sbeck {
85da347917Sbeck 	X509_NAME *iname;
869a659387Stb 	const ASN1_INTEGER *serial;
87da347917Sbeck 	ASN1_BIT_STRING *ikey;
882d2941d0Smiod 
89da347917Sbeck #ifndef OPENSSL_NO_SHA1
902d2941d0Smiod 	if (!dgst)
912d2941d0Smiod 		dgst = EVP_sha1();
92da347917Sbeck #endif
932d2941d0Smiod 	if (subject) {
94da347917Sbeck 		iname = X509_get_issuer_name(subject);
959a659387Stb 		serial = X509_get0_serialNumber(subject);
962d2941d0Smiod 	} else {
97da347917Sbeck 		iname = X509_get_subject_name(issuer);
98da347917Sbeck 		serial = NULL;
99da347917Sbeck 	}
1000c07168cSinoguchi 	if ((ikey = X509_get0_pubkey_bitstr(issuer)) == NULL)
1010c07168cSinoguchi 		return NULL;
1020c07168cSinoguchi 
103da347917Sbeck 	return OCSP_cert_id_new(dgst, iname, ikey, serial);
104da347917Sbeck }
105a1e92f6bSbeck LCRYPTO_ALIAS(OCSP_cert_to_id);
106da347917Sbeck 
1072d2941d0Smiod OCSP_CERTID *
1084394f12dStb OCSP_cert_id_new(const EVP_MD *dgst, const X509_NAME *issuerName,
1094394f12dStb     const ASN1_BIT_STRING *issuerKey, const ASN1_INTEGER *serialNumber)
110da347917Sbeck {
111da347917Sbeck 	int nid;
112da347917Sbeck 	unsigned int i;
113da347917Sbeck 	OCSP_CERTID *cid = NULL;
114da347917Sbeck 	unsigned char md[EVP_MAX_MD_SIZE];
115da347917Sbeck 
116a3eeb048Stb 	if ((cid = OCSP_CERTID_new()) == NULL)
1172d2941d0Smiod 		goto err;
118da347917Sbeck 
1192d2941d0Smiod 	if ((nid = EVP_MD_type(dgst)) == NID_undef) {
1205067ae9fSbeck 		OCSPerror(OCSP_R_UNKNOWN_NID);
121da347917Sbeck 		goto err;
122da347917Sbeck 	}
123a3eeb048Stb 	if (!X509_ALGOR_set0_by_nid(cid->hashAlgorithm, nid, V_ASN1_NULL, NULL))
1242d2941d0Smiod 		goto err;
125da347917Sbeck 
126a3eeb048Stb 	if (!X509_NAME_digest(issuerName, dgst, md, &i)) {
127a3eeb048Stb 		OCSPerror(OCSP_R_DIGEST_ERR);
128a3eeb048Stb 		goto err;
129a3eeb048Stb 	}
130a3eeb048Stb 	if (!ASN1_OCTET_STRING_set(cid->issuerNameHash, md, i))
1312d2941d0Smiod 		goto err;
132da347917Sbeck 
133da347917Sbeck 	/* Calculate the issuerKey hash, excluding tag and length */
1345cdd308eSdjm 	if (!EVP_Digest(issuerKey->data, issuerKey->length, md, &i, dgst, NULL))
1355cdd308eSdjm 		goto err;
136da347917Sbeck 
137a3eeb048Stb 	if (!ASN1_OCTET_STRING_set(cid->issuerKeyHash, md, i))
1382d2941d0Smiod 		goto err;
139da347917Sbeck 
140a3eeb048Stb 	if (serialNumber != NULL) {
141da347917Sbeck 		ASN1_INTEGER_free(cid->serialNumber);
142a3eeb048Stb 		if ((cid->serialNumber = ASN1_INTEGER_dup(serialNumber)) == NULL)
1432d2941d0Smiod 			goto err;
144da347917Sbeck 	}
145a3eeb048Stb 
146da347917Sbeck 	return cid;
147bc775f6cSjsing 
148da347917Sbeck  err:
1492d2941d0Smiod 	OCSP_CERTID_free(cid);
150a3eeb048Stb 
151da347917Sbeck 	return NULL;
152da347917Sbeck }
153a1e92f6bSbeck LCRYPTO_ALIAS(OCSP_cert_id_new);
154da347917Sbeck 
1552d2941d0Smiod int
1562d2941d0Smiod OCSP_id_issuer_cmp(OCSP_CERTID *a, OCSP_CERTID *b)
157da347917Sbeck {
158da347917Sbeck 	int ret;
1592d2941d0Smiod 
160*de5c7f0bStb 	/*
161*de5c7f0bStb 	 * XXX - should we really ignore parameters here? We probably need to
162*de5c7f0bStb 	 * consider omitted parameters and explicit ASN.1 NULL as equal for
163*de5c7f0bStb 	 * the SHAs, so don't blindly switch to X509_ALGOR_cmp().
164*de5c7f0bStb 	 */
165da347917Sbeck 	ret = OBJ_cmp(a->hashAlgorithm->algorithm, b->hashAlgorithm->algorithm);
1662d2941d0Smiod 	if (ret)
1672d2941d0Smiod 		return ret;
168da347917Sbeck 	ret = ASN1_OCTET_STRING_cmp(a->issuerNameHash, b->issuerNameHash);
1692d2941d0Smiod 	if (ret)
1702d2941d0Smiod 		return ret;
171da347917Sbeck 	return ASN1_OCTET_STRING_cmp(a->issuerKeyHash, b->issuerKeyHash);
172da347917Sbeck }
173a1e92f6bSbeck LCRYPTO_ALIAS(OCSP_id_issuer_cmp);
174da347917Sbeck 
1752d2941d0Smiod int
1762d2941d0Smiod OCSP_id_cmp(OCSP_CERTID *a, OCSP_CERTID *b)
177da347917Sbeck {
178da347917Sbeck 	int ret;
1792d2941d0Smiod 
180da347917Sbeck 	ret = OCSP_id_issuer_cmp(a, b);
1812d2941d0Smiod 	if (ret)
1822d2941d0Smiod 		return ret;
183da347917Sbeck 	return ASN1_INTEGER_cmp(a->serialNumber, b->serialNumber);
184da347917Sbeck }
185a1e92f6bSbeck LCRYPTO_ALIAS(OCSP_id_cmp);
186da347917Sbeck 
187da347917Sbeck /* Parse a URL and split it up into host, port and path components and whether
188da347917Sbeck  * it is SSL.
189da347917Sbeck  */
1902d2941d0Smiod int
19114edca61Stb OCSP_parse_url(const char *url, char **phost, char **pport, char **ppath,
19214edca61Stb     int *pssl)
193da347917Sbeck {
19457887ff9Sbeck 	char *host, *path, *port, *tmp;
195da347917Sbeck 
19657887ff9Sbeck 	*phost = *pport = *ppath = NULL;
197da347917Sbeck 	*pssl = 0;
19857887ff9Sbeck 
19957887ff9Sbeck 	if (strncmp(url, "https://", 8) == 0) {
200da347917Sbeck 		*pssl = 1;
20157887ff9Sbeck 		host = strdup(url + 8);
20257887ff9Sbeck 	} else if (strncmp(url, "http://", 7) == 0)
20357887ff9Sbeck 		host = strdup(url + 7);
2042d2941d0Smiod 	else {
2055067ae9fSbeck 		OCSPerror(OCSP_R_ERROR_PARSING_URL);
20657887ff9Sbeck 		return 0;
20757887ff9Sbeck 	}
20857887ff9Sbeck 	if (host == NULL) {
2095067ae9fSbeck 		OCSPerror(ERR_R_MALLOC_FAILURE);
210da347917Sbeck 		return 0;
211da347917Sbeck 	}
2120a5d6edeSdjm 
21357887ff9Sbeck 	if ((tmp = strchr(host, '/')) != NULL) {
21457887ff9Sbeck 		path = strdup(tmp);
21557887ff9Sbeck 		*tmp = '\0';
21657887ff9Sbeck 	} else
21757887ff9Sbeck 		path = strdup("/");
21857887ff9Sbeck 
21957887ff9Sbeck 	if ((tmp = strchr(host, ':')) != NULL ) {
22057887ff9Sbeck 		port = strdup(tmp + 1);
22157887ff9Sbeck 		*tmp = '\0';
22257887ff9Sbeck 	} else {
22357887ff9Sbeck 		if (*pssl)
22457887ff9Sbeck 			port = strdup("443");
22557887ff9Sbeck 		else
22657887ff9Sbeck 			port = strdup("80");
22757887ff9Sbeck 	}
22857887ff9Sbeck 
22957887ff9Sbeck 	if (path == NULL || port == NULL) {
23057887ff9Sbeck 		free(host);
23157887ff9Sbeck 		free(path);
23257887ff9Sbeck 		free(port);
2335067ae9fSbeck 		OCSPerror(ERR_R_MALLOC_FAILURE);
23457887ff9Sbeck 		return 0;
23557887ff9Sbeck 	}
23657887ff9Sbeck 
23757887ff9Sbeck 	*phost = host;
23857887ff9Sbeck 	*ppath = path;
23957887ff9Sbeck 	*pport = port;
24057887ff9Sbeck 	return 1;
24157887ff9Sbeck }
242a1e92f6bSbeck LCRYPTO_ALIAS(OCSP_parse_url);
2435cfcf2a1Sjsing 
2445cfcf2a1Sjsing OCSP_CERTID *
2455cfcf2a1Sjsing OCSP_CERTID_dup(OCSP_CERTID *x)
2465cfcf2a1Sjsing {
247589a2d47Sjsing 	return ASN1_item_dup(&OCSP_CERTID_it, x);
2485cfcf2a1Sjsing }
249a1e92f6bSbeck LCRYPTO_ALIAS(OCSP_CERTID_dup);
250