diff --git a/content/fetchers/about/certificate.c b/content/fetchers/about/certificate.c index 6f634d22a..554f06eb8 100644 --- a/content/fetchers/about/certificate.c +++ b/content/fetchers/about/certificate.c @@ -134,29 +134,26 @@ static nserror free_ns_cert_info(struct ns_cert_info *cinfo) #include #include -#if (OPENSSL_VERSION_NUMBER < 0x30000000L) -/* OpenSSL 1.1.1 or LibreSSL */ +/* OpenSSL 1.0.x, 1.0.2, 1.1.0 and 1.1.1 API all changed + * LibreSSL declares its OpenSSL version as 2.1 but only supports 1.0.x API + */ +#if (defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x1010000fL)) +/* 1.0.x */ -# if defined(LIBRESSL_VERSION_NUMBER) - /* LibreSSL */ -# if (LIBRESSL_VERSION_NUMBER < 0x3050000fL) - /* LibreSSL <3.5.0 */ - -# if (LIBRESSL_VERSION_NUMBER < 0x2070000fL) - /* LibreSSL <2.7.0 */ +#if (defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x1000200fL)) +/* pre 1.0.2 */ static int ns_X509_get_signature_nid(X509 *cert) { return OBJ_obj2nid(cert->cert_info->key->algor->algorithm); } +#else +#define ns_X509_get_signature_nid X509_get_signature_nid +#endif static const unsigned char *ns_ASN1_STRING_get0_data(ASN1_STRING *asn1str) { return (const unsigned char *)ASN1_STRING_data(asn1str); } -# else -# define ns_X509_get_signature_nid X509_get_signature_nid -# define ns_ASN1_STRING_get0_data ASN1_STRING_get0_data -# endif static const BIGNUM *ns_RSA_get0_n(const RSA *d) { @@ -167,20 +164,298 @@ static const BIGNUM *ns_RSA_get0_e(const RSA *d) { return d->e; } -# else - /* LibreSSL >= 3.5.0 */ -# define ns_X509_get_signature_nid X509_get_signature_nid -# define ns_ASN1_STRING_get0_data ASN1_STRING_get0_data -# define ns_RSA_get0_n RSA_get0_n -# define ns_RSA_get0_e RSA_get0_e -# endif -# else - /* OpenSSL 1.1.1 */ -# define ns_X509_get_signature_nid X509_get_signature_nid -# define ns_ASN1_STRING_get0_data ASN1_STRING_get0_data -# define ns_RSA_get0_n RSA_get0_n -# define ns_RSA_get0_e RSA_get0_e -# endif + +static int ns_EVP_PKEY_get_bn_param(const EVP_PKEY *pkey, + const char *key_name, BIGNUM **bn) { + RSA *rsa; + BIGNUM *result = NULL; + + /* Check parameters: only support allocation-form *bn */ + if (pkey == NULL || key_name == NULL || bn == NULL || *bn != NULL) + return 0; + + /* Only support RSA keys */ + if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) + return 0; + + rsa = EVP_PKEY_get1_RSA((EVP_PKEY *) pkey); + if (rsa == NULL) + return 0; + + if (strcmp(key_name, "n") == 0) { + const BIGNUM *n = ns_RSA_get0_n(rsa); + if (n != NULL) + result = BN_dup(n); + } else if (strcmp(key_name, "e") == 0) { + const BIGNUM *e = ns_RSA_get0_e(rsa); + if (e != NULL) + result = BN_dup(e); + } + + RSA_free(rsa); + + *bn = result; + + return (result != NULL) ? 1 : 0; +} + +static int ns_EVP_PKEY_get_utf8_string_param(const EVP_PKEY *pkey, + const char *key_name, char *str, size_t max_len, + size_t *out_len) +{ + const EC_GROUP *ecgroup; + const char *group; + EC_KEY *ec; + int ret = 0; + + if (pkey == NULL || key_name == NULL) + return 0; + + /* Only support EC keys */ + if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) + return 0; + + /* Only support fetching the group */ + if (strcmp(key_name, "group") != 0) + return 0; + + ec = EVP_PKEY_get1_EC_KEY((EVP_PKEY *) pkey); + + ecgroup = EC_KEY_get0_group(ec); + if (ecgroup == NULL) { + group = ""; + } else { + group = OBJ_nid2ln(EC_GROUP_get_curve_name(ecgroup)); + } + + if (str != NULL && max_len > strlen(group)) { + strcpy(str, group); + str[strlen(group)] = '\0'; + ret = 1; + } + if (out_len != NULL) + *out_len = strlen(group); + + EC_KEY_free(ec); + + return ret; +} + +static int ns_EVP_PKEY_get_octet_string_param(const EVP_PKEY *pkey, + const char *key_name, unsigned char *buf, size_t max_len, + size_t *out_len) +{ + const EC_GROUP *ecgroup; + const EC_POINT *ecpoint; + size_t len; + BN_CTX *bnctx; + EC_KEY *ec; + int ret = 0; + + if (pkey == NULL || key_name == NULL) + return 0; + + /* Only support EC keys */ + if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) + return 0; + + if (strcmp(key_name, "encoded-pub-key") != 0) + return 0; + + ec = EVP_PKEY_get1_EC_KEY((EVP_PKEY *) pkey); + if (ec == NULL) + return 0; + + ecgroup = EC_KEY_get0_group(ec); + if (ecgroup != NULL) { + ecpoint = EC_KEY_get0_public_key(ec); + if (ecpoint != NULL) { + bnctx = BN_CTX_new(); + len = EC_POINT_point2oct(ecgroup, + ecpoint, + POINT_CONVERSION_UNCOMPRESSED, + NULL, + 0, + bnctx); + if (len != 0 && len <= max_len) { + if (EC_POINT_point2oct(ecgroup, + ecpoint, + POINT_CONVERSION_UNCOMPRESSED, + buf, + len, + bnctx) == len) + ret = 1; + } + if (out_len != NULL) + *out_len = len; + BN_CTX_free(bnctx); + } + } + + EC_KEY_free(ec); + + return ret; +} +#elif (OPENSSL_VERSION_NUMBER < 0x1010100fL) +/* 1.1.0 */ +#define ns_X509_get_signature_nid X509_get_signature_nid +#define ns_ASN1_STRING_get0_data ASN1_STRING_get0_data + +static const BIGNUM *ns_RSA_get0_n(const RSA *r) +{ + const BIGNUM *n; + const BIGNUM *e; + const BIGNUM *d; + RSA_get0_key(r, &n, &e, &d); + return n; +} + +static const BIGNUM *ns_RSA_get0_e(const RSA *r) +{ + const BIGNUM *n; + const BIGNUM *e; + const BIGNUM *d; + RSA_get0_key(r, &n, &e, &d); + return e; +} + +static int ns_EVP_PKEY_get_bn_param(const EVP_PKEY *pkey, + const char *key_name, BIGNUM **bn) { + RSA *rsa; + BIGNUM *result = NULL; + + /* Check parameters: only support allocation-form *bn */ + if (pkey == NULL || key_name == NULL || bn == NULL || *bn != NULL) + return 0; + + /* Only support RSA keys */ + if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) + return 0; + + rsa = EVP_PKEY_get1_RSA((EVP_PKEY *) pkey); + if (rsa == NULL) + return 0; + + if (strcmp(key_name, "n") == 0) { + const BIGNUM *n = ns_RSA_get0_n(rsa); + if (n != NULL) + result = BN_dup(n); + } else if (strcmp(key_name, "e") == 0) { + const BIGNUM *e = ns_RSA_get0_e(rsa); + if (e != NULL) + result = BN_dup(e); + } + + RSA_free(rsa); + + *bn = result; + + return (result != NULL) ? 1 : 0; +} + +static int ns_EVP_PKEY_get_utf8_string_param(const EVP_PKEY *pkey, + const char *key_name, char *str, size_t max_len, + size_t *out_len) +{ + const EC_GROUP *ecgroup; + const char *group; + EC_KEY *ec; + int ret = 0; + + if (pkey == NULL || key_name == NULL) + return 0; + + /* Only support EC keys */ + if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) + return 0; + + /* Only support fetching the group */ + if (strcmp(key_name, "group") != 0) + return 0; + + ec = EVP_PKEY_get1_EC_KEY((EVP_PKEY *) pkey); + + ecgroup = EC_KEY_get0_group(ec); + if (ecgroup == NULL) { + group = ""; + } else { + group = OBJ_nid2ln(EC_GROUP_get_curve_name(ecgroup)); + } + + if (str != NULL && max_len > strlen(group)) { + strcpy(str, group); + str[strlen(group)] = '\0'; + ret = 1; + } + if (out_len != NULL) + *out_len = strlen(group); + + EC_KEY_free(ec); + + return ret; +} + +static int ns_EVP_PKEY_get_octet_string_param(const EVP_PKEY *pkey, + const char *key_name, unsigned char *buf, size_t max_len, + size_t *out_len) +{ + const EC_GROUP *ecgroup; + const EC_POINT *ecpoint; + size_t len; + BN_CTX *bnctx; + EC_KEY *ec; + int ret = 0; + + if (pkey == NULL || key_name == NULL) + return 0; + + /* Only support EC keys */ + if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) + return 0; + + if (strcmp(key_name, "encoded-pub-key") != 0) + return 0; + + ec = EVP_PKEY_get1_EC_KEY((EVP_PKEY *) pkey); + if (ec == NULL) + return 0; + + ecgroup = EC_KEY_get0_group(ec); + if (ecgroup != NULL) { + ecpoint = EC_KEY_get0_public_key(ec); + if (ecpoint != NULL) { + bnctx = BN_CTX_new(); + len = EC_POINT_point2oct(ecgroup, + ecpoint, + POINT_CONVERSION_UNCOMPRESSED, + NULL, + 0, + bnctx); + if (len != 0 && len <= max_len) { + if (EC_POINT_point2oct(ecgroup, + ecpoint, + POINT_CONVERSION_UNCOMPRESSED, + buf, + len, + bnctx) == len) + ret = 1; + } + if (out_len != NULL) + *out_len = len; + BN_CTX_free(bnctx); + } + } + + EC_KEY_free(ec); + + return ret; +} +#elif (OPENSSL_VERSION_NUMBER < 0x30000000L) +/* 1.1.1 */ +#define ns_X509_get_signature_nid X509_get_signature_nid +#define ns_ASN1_STRING_get0_data ASN1_STRING_get0_data +#define ns_RSA_get0_n RSA_get0_n +#define ns_RSA_get0_e RSA_get0_e static int ns_EVP_PKEY_get_bn_param(const EVP_PKEY *pkey, const char *key_name, BIGNUM **bn) { @@ -314,7 +589,7 @@ static int ns_EVP_PKEY_get_octet_string_param(const EVP_PKEY *pkey, return ret; } #else -/* OpenSSL 3.x and later */ +/* 3.x and later */ #define ns_X509_get_signature_nid X509_get_signature_nid #define ns_ASN1_STRING_get0_data ASN1_STRING_get0_data #define ns_RSA_get0_n RSA_get0_n diff --git a/content/fetchers/curl.c b/content/fetchers/curl.c index b1907448e..6878d9e6a 100644 --- a/content/fetchers/curl.c +++ b/content/fetchers/curl.c @@ -106,11 +106,33 @@ #include #include +/* OpenSSL 1.0.x to 1.1.0 certificate reference counting changed + * LibreSSL declares its OpenSSL version as 2.1 but only supports the old way + */ +#if (defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x1010000fL)) +static int ns_X509_up_ref(X509 *cert) +{ + cert->references++; + return 1; +} + +static void ns_X509_free(X509 *cert) +{ + cert->references--; + if (cert->references == 0) { + X509_free(cert); + } +} +#else +#define ns_X509_up_ref X509_up_ref +#define ns_X509_free X509_free +#endif + #else /* WITH_OPENSSL */ typedef char X509; -static void X509_free(X509 *cert) +static void ns_X509_free(X509 *cert) { free(cert); } @@ -731,7 +753,7 @@ fetch_curl_verify_callback(int verify_ok, X509_STORE_CTX *x509_ctx) */ if (!fetch->cert_data[depth].cert) { fetch->cert_data[depth].cert = X509_STORE_CTX_get_current_cert(x509_ctx); - X509_up_ref(fetch->cert_data[depth].cert); + ns_X509_up_ref(fetch->cert_data[depth].cert); fetch->cert_data[depth].err = X509_STORE_CTX_get_error(x509_ctx); } @@ -1456,7 +1478,7 @@ static void fetch_curl_free(void *vf) /* free certificate data */ for (i = 0; i < MAX_CERT_DEPTH; i++) { if (f->cert_data[i].cert != NULL) { - X509_free(f->cert_data[i].cert); + ns_X509_free(f->cert_data[i].cert); } }