Branch data Line data Source code
1 : : /* 2 : : * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 : : * 4 : : * Licensed under the Apache License, Version 2.0 (the "License"). 5 : : * You may not use this file except in compliance with the License. 6 : : * A copy of the License is located at 7 : : * 8 : : * http://aws.amazon.com/apache2.0 9 : : * 10 : : * or in the "license" file accompanying this file. This file is distributed 11 : : * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 : : * express or implied. See the License for the specific language governing 13 : : * permissions and limitations under the License. 14 : : */ 15 : : 16 : : #include "crypto/s2n_openssl_x509.h" 17 : : 18 : : #include "api/s2n.h" 19 : : #include "crypto/s2n_mldsa.h" 20 : : 21 : : DEFINE_POINTER_CLEANUP_FUNC(EVP_PKEY *, EVP_PKEY_free); 22 : : DEFINE_POINTER_CLEANUP_FUNC(EC_KEY *, EC_KEY_free); 23 : : 24 : : S2N_CLEANUP_RESULT s2n_openssl_x509_stack_pop_free(STACK_OF(X509) **cert_chain) 25 : 0 : { 26 [ # # ][ # # ]: 0 : RESULT_ENSURE_REF(*cert_chain); 27 : 0 : sk_X509_pop_free(*cert_chain, X509_free); 28 : 0 : *cert_chain = NULL; 29 : 0 : return S2N_RESULT_OK; 30 : 0 : } 31 : : 32 : : S2N_CLEANUP_RESULT s2n_openssl_asn1_time_free_pointer(ASN1_GENERALIZEDTIME **time_ptr) 33 : 23 : { 34 : : /* The ANS1_*TIME structs are just typedef wrappers around ASN1_STRING 35 : : * 36 : : * The ASN1_TIME, ASN1_UTCTIME and ASN1_GENERALIZEDTIME structures are 37 : : * represented as an ASN1_STRING internally and can be freed up using 38 : : * ASN1_STRING_free(). 39 : : * https://www.openssl.org/docs/man1.1.1/man3/ASN1_TIME_to_tm.html 40 : : */ 41 [ # # ][ - + ]: 23 : RESULT_ENSURE_REF(*time_ptr); 42 : 23 : ASN1_STRING_free((ASN1_STRING *) *time_ptr); 43 : 23 : *time_ptr = NULL; 44 : 23 : return S2N_RESULT_OK; 45 : 23 : } 46 : : 47 : : S2N_RESULT s2n_openssl_x509_parse_impl(struct s2n_blob *asn1der, X509 **cert_out, uint32_t *parsed_length) 48 : 14948 : { 49 [ # # ][ - + ]: 14948 : RESULT_ENSURE_REF(asn1der); 50 [ - + ][ # # ]: 14948 : RESULT_ENSURE_REF(asn1der->data); 51 [ - + ][ # # ]: 14948 : RESULT_ENSURE_REF(cert_out); 52 [ - + ][ # # ]: 14948 : RESULT_ENSURE_REF(parsed_length); 53 : : 54 : 14948 : uint8_t *cert_to_parse = asn1der->data; 55 : 14948 : *cert_out = d2i_X509(NULL, (const unsigned char **) (void *) &cert_to_parse, asn1der->size); 56 [ + + ][ + - ]: 14948 : RESULT_ENSURE(*cert_out != NULL, S2N_ERR_DECODE_CERTIFICATE); 57 : : 58 : : /* If cert parsing is successful, d2i_X509 increments *cert_to_parse to the byte following the parsed data */ 59 : 14947 : *parsed_length = cert_to_parse - asn1der->data; 60 : : 61 : 14947 : return S2N_RESULT_OK; 62 : 14948 : } 63 : : 64 : : S2N_RESULT s2n_openssl_x509_parse_without_length_validation(struct s2n_blob *asn1der, X509 **cert_out) 65 : 7914 : { 66 [ - + ][ # # ]: 7914 : RESULT_ENSURE_REF(asn1der); 67 [ - + ][ # # ]: 7914 : RESULT_ENSURE_REF(cert_out); 68 : : 69 : 7914 : uint32_t parsed_len = 0; 70 [ - + ]: 7914 : RESULT_GUARD(s2n_openssl_x509_parse_impl(asn1der, cert_out, &parsed_len)); 71 : : 72 : 7914 : return S2N_RESULT_OK; 73 : 7914 : } 74 : : 75 : : S2N_RESULT s2n_openssl_x509_parse(struct s2n_blob *asn1der, X509 **cert_out) 76 : 7034 : { 77 [ - + ][ # # ]: 7034 : RESULT_ENSURE_REF(asn1der); 78 [ # # ][ - + ]: 7034 : RESULT_ENSURE_REF(cert_out); 79 : : 80 : 7034 : uint32_t parsed_len = 0; 81 [ + + ]: 7034 : RESULT_GUARD(s2n_openssl_x509_parse_impl(asn1der, cert_out, &parsed_len)); 82 : : 83 : : /* Some TLS clients in the wild send extra trailing bytes after the Certificate. 84 : : * Allow this in s2n for backwards compatibility with existing clients. */ 85 : 7033 : uint32_t trailing_bytes = asn1der->size - parsed_len; 86 [ + - ][ + + ]: 7033 : RESULT_ENSURE(trailing_bytes <= S2N_MAX_ALLOWED_CERT_TRAILING_BYTES, S2N_ERR_DECODE_CERTIFICATE); 87 : : 88 : 7031 : return S2N_RESULT_OK; 89 : 7033 : } 90 : : 91 : : S2N_RESULT s2n_openssl_x509_get_cert_info(X509 *cert, struct s2n_cert_info *info) 92 : 3068 : { 93 [ # # ][ - + ]: 3068 : RESULT_ENSURE_REF(cert); 94 [ # # ][ - + ]: 3068 : RESULT_ENSURE_REF(info); 95 : : 96 : 3068 : X509_NAME *issuer_name = X509_get_issuer_name(cert); 97 [ # # ][ - + ]: 3068 : RESULT_ENSURE_REF(issuer_name); 98 : : 99 : 3068 : X509_NAME *subject_name = X509_get_subject_name(cert); 100 [ # # ][ - + ]: 3068 : RESULT_ENSURE_REF(subject_name); 101 : : 102 [ + + ]: 3068 : if (X509_NAME_cmp(issuer_name, subject_name) == 0) { 103 : 1232 : info->self_signed = true; 104 : 1836 : } else { 105 : 1836 : info->self_signed = false; 106 : 1836 : } 107 : : 108 : : #if defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER < 0x02070000f) 109 : : RESULT_ENSURE_REF(cert->sig_alg); 110 : : info->signature_nid = OBJ_obj2nid(cert->sig_alg->algorithm); 111 : : #else 112 : 3068 : info->signature_nid = X509_get_signature_nid(cert); 113 : 3068 : #endif 114 : : 115 : : /* There is no method to directly retrieve the signature digest from the X509* 116 : : * that is available in all libcryptos, so instead we use find_sigid_algs. For 117 : : * a signature with NID_ecdsa_with_SHA256 this will return NID_SHA256 118 : : * 119 : : * signature_digest_nid may not always be set. ML-DSA does not have an associated digest. 120 : : */ 121 : 3068 : int find_result = OBJ_find_sigid_algs(info->signature_nid, &info->signature_digest_nid, NULL); 122 [ - + ]: 3068 : if (find_result != 1) { 123 : : /* OBJ_find_sigid_algs may fail for ML-DSA-44 and ML-DSA-87, depending on the 124 : : * version of AWS-LC. See https://github.com/aws/aws-lc/issues/2347. 125 : : * 126 : : * In order to handle this bug, we interpret failures from OBJ_find_sigid_algs 127 : : * as signature_digest_nid==0, which is equivalent to an undefined digest. 128 : : */ 129 : 0 : info->signature_digest_nid = 0; 130 : 0 : } 131 : : 132 : 3068 : DEFER_CLEANUP(EVP_PKEY *pubkey = X509_get_pubkey(cert), EVP_PKEY_free_pointer); 133 [ - + ][ # # ]: 3068 : RESULT_ENSURE(pubkey != NULL, S2N_ERR_DECODE_CERTIFICATE); 134 : : 135 : 3068 : info->public_key_bits = EVP_PKEY_bits(pubkey); 136 [ - + ][ # # ]: 3068 : RESULT_ENSURE(info->public_key_bits > 0, S2N_ERR_CERT_TYPE_UNSUPPORTED); 137 : : 138 [ + + ]: 3068 : if (EVP_PKEY_base_id(pubkey) == EVP_PKEY_EC) { 139 : 715 : DEFER_CLEANUP(EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(pubkey), EC_KEY_free_pointer); 140 [ # # ][ - + ]: 715 : RESULT_ENSURE_REF(ec_key); 141 : 715 : const EC_GROUP *ec_group = EC_KEY_get0_group(ec_key); 142 [ - + ][ # # ]: 715 : RESULT_ENSURE_REF(ec_group); 143 : 715 : info->public_key_nid = EC_GROUP_get_curve_name(ec_group); 144 : : #if S2N_LIBCRYPTO_SUPPORTS_MLDSA 145 : : } else if (EVP_PKEY_base_id(pubkey) == EVP_PKEY_PQDSA) { 146 : : /* EVP_PKEY_base_id() returns the generic EVP_PKEY_PQDSA for all ML-DSA 147 : : * variants. Use EVP_PKEY_pqdsa_get_type() to get the specific 148 : : * parameter-set NID (NID_MLDSA44, NID_MLDSA65, or NID_MLDSA87). 149 : : */ 150 : : info->public_key_nid = EVP_PKEY_pqdsa_get_type(pubkey); 151 : : #endif 152 : 2353 : } else { 153 : 2353 : info->public_key_nid = EVP_PKEY_id(pubkey); 154 : 2353 : } 155 [ - + ][ # # ]: 3068 : RESULT_ENSURE(info->public_key_nid != NID_undef, S2N_ERR_CERT_TYPE_UNSUPPORTED); 156 : : 157 : 3068 : return S2N_RESULT_OK; 158 : 3068 : }