crypto/ocsp/ocsp_lib.c (196 lines of code) (raw):
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC
#include <openssl/mem.h>
#include <string.h>
#include "internal.h"
OCSP_CERTID *OCSP_cert_to_id(const EVP_MD *dgst, const X509 *subject,
const X509 *issuer) {
if (issuer == NULL) {
OPENSSL_PUT_ERROR(OCSP, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
const X509_NAME *iname;
const ASN1_INTEGER *serial;
ASN1_BIT_STRING *ikey;
if (dgst == NULL) {
dgst = EVP_sha1();
}
if (subject != NULL) {
iname = X509_get_issuer_name(subject);
serial = X509_get0_serialNumber(subject);
} else {
iname = X509_get_subject_name(issuer);
serial = NULL;
}
ikey = X509_get0_pubkey_bitstr(issuer);
return OCSP_cert_id_new(dgst, iname, ikey, serial);
}
OCSP_CERTID *OCSP_cert_id_new(const EVP_MD *dgst, const X509_NAME *issuerName,
const ASN1_BIT_STRING *issuerKey,
const ASN1_INTEGER *serialNumber) {
if (dgst == NULL || issuerName == NULL || issuerKey == NULL) {
OPENSSL_PUT_ERROR(OCSP, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
int nid;
unsigned int i;
X509_ALGOR *alg;
unsigned char md[EVP_MAX_MD_SIZE];
OCSP_CERTID *cid = OCSP_CERTID_new();
if (cid == NULL) {
return NULL;
}
alg = cid->hashAlgorithm;
ASN1_OBJECT_free(alg->algorithm);
nid = EVP_MD_type(dgst);
if (nid == NID_undef) {
OPENSSL_PUT_ERROR(OCSP, OCSP_R_UNKNOWN_NID);
goto err;
}
alg->algorithm = OBJ_nid2obj(nid);
if (alg->algorithm == NULL) {
goto err;
}
alg->parameter = ASN1_TYPE_new();
if (alg->parameter == NULL) {
goto err;
}
alg->parameter->type = V_ASN1_NULL;
if (!X509_NAME_digest(issuerName, dgst, md, &i)) {
OPENSSL_PUT_ERROR(OCSP, OCSP_R_DIGEST_ERR);
goto err;
}
if (!(ASN1_OCTET_STRING_set(cid->issuerNameHash, md, i))) {
goto err;
}
// Calculate the issuerKey hash, excluding tag and length
if (!EVP_Digest(issuerKey->data, issuerKey->length, md, &i, dgst, NULL)) {
goto err;
}
if (!(ASN1_OCTET_STRING_set(cid->issuerKeyHash, md, i))) {
goto err;
}
// Only copy |serialNumber| if available. This may be empty.
if (serialNumber != NULL) {
if (ASN1_STRING_copy(cid->serialNumber, serialNumber) == 0) {
goto err;
}
}
return cid;
err:
OCSP_CERTID_free(cid);
return NULL;
}
int OCSP_id_issuer_cmp(const OCSP_CERTID *a, const OCSP_CERTID *b) {
if (a == NULL || b == NULL) {
OPENSSL_PUT_ERROR(OCSP, ERR_R_PASSED_NULL_PARAMETER);
return -1;
}
if (a->hashAlgorithm == NULL || b->hashAlgorithm == NULL) {
OPENSSL_PUT_ERROR(OCSP, ERR_R_PASSED_NULL_PARAMETER);
return -1;
}
int ret = OBJ_cmp(a->hashAlgorithm->algorithm, b->hashAlgorithm->algorithm);
if (ret != 0) {
return ret;
}
ret = ASN1_OCTET_STRING_cmp(a->issuerNameHash, b->issuerNameHash);
if (ret != 0) {
return ret;
}
ret = ASN1_OCTET_STRING_cmp(a->issuerKeyHash, b->issuerKeyHash);
return ret;
}
int OCSP_id_cmp(const OCSP_CERTID *a, const OCSP_CERTID *b) {
if (a == NULL || b == NULL) {
OPENSSL_PUT_ERROR(OCSP, ERR_R_PASSED_NULL_PARAMETER);
return -1;
}
// Compare OCSP issuer name and key
int ret = OCSP_id_issuer_cmp(a, b);
if (ret != 0) {
return ret;
}
// Compare certificate serialNumber
ret = ASN1_INTEGER_cmp(a->serialNumber, b->serialNumber);
return ret;
}
int OCSP_parse_url(const char *url, char **phost, char **pport, char **ppath,
int *pssl) {
if (url == NULL || phost == NULL || pport == NULL || ppath == NULL ||
pssl == NULL) {
OPENSSL_PUT_ERROR(OCSP, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
char *parser, *buffer;
char *host = NULL;
char *port = NULL;
*phost = NULL;
*pport = NULL;
*ppath = NULL;
// Duplicate into the buffer since the contents are going to be changed.
buffer = OPENSSL_strdup(url);
if (buffer == NULL) {
goto mem_err;
}
// Check for initial colon
parser = strchr(buffer, ':');
if (parser == NULL) {
goto parse_err;
}
*(parser++) = '\0';
// Set default ports for http and https. If a port is specified later, this
// will be overwritten. |pssl| will be set to true, if https is being used.
if (strncmp(buffer, "https", 5) == 0) {
*pssl = 1;
port = (char *)"443";
} else if (strncmp(buffer, "http", 4) == 0) {
*pssl = 0;
port = (char *)"80";
} else {
goto parse_err;
}
// Check for double slash.
if ((parser[0] != '/') || (parser[1] != '/')) {
goto parse_err;
}
parser += 2;
host = parser;
// Check for trailing part of path.
parser = strchr(parser, '/');
if (parser == NULL) {
// Default is "/" if there is no trailing path in the URL.
*ppath = OPENSSL_strdup("/");
} else {
*ppath = OPENSSL_strdup(parser);
// Set start of path to 0 so hostname is valid.
*parser = '\0';
}
if (*ppath == NULL) {
goto mem_err;
}
parser = host;
// Checks if the host is an ipv6 host address.
if (host[0] == '[') {
host++;
parser = strchr(host, ']');
if (parser == NULL) {
goto parse_err;
}
*parser = '\0';
parser++;
}
// Look for optional ':' for port number.
if ((parser = strchr(parser, ':'))) {
*parser = 0;
port = parser + 1;
}
*pport = OPENSSL_strdup(port);
if (*pport == NULL) {
goto mem_err;
}
*phost = OPENSSL_strdup(host);
if (*phost == NULL) {
goto mem_err;
}
OPENSSL_free(buffer);
return 1;
mem_err:
OPENSSL_PUT_ERROR(OCSP, ERR_R_MALLOC_FAILURE);
goto err;
parse_err:
OPENSSL_PUT_ERROR(OCSP, OCSP_R_ERROR_PARSING_URL);
err:
OPENSSL_free(buffer);
OPENSSL_free(*ppath);
*ppath = NULL;
OPENSSL_free(*pport);
*pport = NULL;
OPENSSL_free(*phost);
*phost = NULL;
return 0;
}