LCOV - code coverage report
Current view: top level - crypto - s2n_openssl_x509.c (source / functions) Hit Total Coverage
Test: unit_test_coverage.info Lines: 71 73 97.3 %
Date: 2025-08-15 07:28:39 Functions: 6 6 100.0 %
Branches: 33 94 35.1 %

           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                 :            : 
      20                 :            : DEFINE_POINTER_CLEANUP_FUNC(EVP_PKEY *, EVP_PKEY_free);
      21                 :            : DEFINE_POINTER_CLEANUP_FUNC(EC_KEY *, EC_KEY_free);
      22                 :            : 
      23                 :            : S2N_CLEANUP_RESULT s2n_openssl_x509_stack_pop_free(STACK_OF(X509) **cert_chain)
      24                 :        250 : {
      25 [ -  + ][ #  # ]:        250 :     RESULT_ENSURE_REF(*cert_chain);
      26                 :        250 :     sk_X509_pop_free(*cert_chain, X509_free);
      27                 :        250 :     *cert_chain = NULL;
      28                 :        250 :     return S2N_RESULT_OK;
      29                 :        250 : }
      30                 :            : 
      31                 :            : S2N_CLEANUP_RESULT s2n_openssl_asn1_time_free_pointer(ASN1_GENERALIZEDTIME **time_ptr)
      32                 :         23 : {
      33                 :            :     /* The ANS1_*TIME structs are just typedef wrappers around ASN1_STRING
      34                 :            :      *
      35                 :            :      * The ASN1_TIME, ASN1_UTCTIME and ASN1_GENERALIZEDTIME structures are
      36                 :            :      * represented as an ASN1_STRING internally and can be freed up using
      37                 :            :      * ASN1_STRING_free().
      38                 :            :      * https://www.openssl.org/docs/man1.1.1/man3/ASN1_TIME_to_tm.html
      39                 :            :      */
      40 [ #  # ][ -  + ]:         23 :     RESULT_ENSURE_REF(*time_ptr);
      41                 :         23 :     ASN1_STRING_free((ASN1_STRING *) *time_ptr);
      42                 :         23 :     *time_ptr = NULL;
      43                 :         23 :     return S2N_RESULT_OK;
      44                 :         23 : }
      45                 :            : 
      46                 :            : S2N_RESULT s2n_openssl_x509_parse_impl(struct s2n_blob *asn1der, X509 **cert_out, uint32_t *parsed_length)
      47                 :      13384 : {
      48 [ #  # ][ -  + ]:      13384 :     RESULT_ENSURE_REF(asn1der);
      49 [ -  + ][ #  # ]:      13384 :     RESULT_ENSURE_REF(asn1der->data);
      50 [ -  + ][ #  # ]:      13384 :     RESULT_ENSURE_REF(cert_out);
      51 [ -  + ][ #  # ]:      13384 :     RESULT_ENSURE_REF(parsed_length);
      52                 :            : 
      53                 :      13384 :     uint8_t *cert_to_parse = asn1der->data;
      54                 :      13384 :     *cert_out = d2i_X509(NULL, (const unsigned char **) (void *) &cert_to_parse, asn1der->size);
      55 [ +  + ][ +  - ]:      13384 :     RESULT_ENSURE(*cert_out != NULL, S2N_ERR_DECODE_CERTIFICATE);
      56                 :            : 
      57                 :            :     /* If cert parsing is successful, d2i_X509 increments *cert_to_parse to the byte following the parsed data */
      58                 :      13383 :     *parsed_length = cert_to_parse - asn1der->data;
      59                 :            : 
      60                 :      13383 :     return S2N_RESULT_OK;
      61                 :      13384 : }
      62                 :            : 
      63                 :            : S2N_RESULT s2n_openssl_x509_parse_without_length_validation(struct s2n_blob *asn1der, X509 **cert_out)
      64                 :       7401 : {
      65 [ -  + ][ #  # ]:       7401 :     RESULT_ENSURE_REF(asn1der);
      66 [ -  + ][ #  # ]:       7401 :     RESULT_ENSURE_REF(cert_out);
      67                 :            : 
      68                 :       7401 :     uint32_t parsed_len = 0;
      69         [ -  + ]:       7401 :     RESULT_GUARD(s2n_openssl_x509_parse_impl(asn1der, cert_out, &parsed_len));
      70                 :            : 
      71                 :       7401 :     return S2N_RESULT_OK;
      72                 :       7401 : }
      73                 :            : 
      74                 :            : S2N_RESULT s2n_openssl_x509_parse(struct s2n_blob *asn1der, X509 **cert_out)
      75                 :       5983 : {
      76 [ -  + ][ #  # ]:       5983 :     RESULT_ENSURE_REF(asn1der);
      77 [ #  # ][ -  + ]:       5983 :     RESULT_ENSURE_REF(cert_out);
      78                 :            : 
      79                 :       5983 :     uint32_t parsed_len = 0;
      80         [ +  + ]:       5983 :     RESULT_GUARD(s2n_openssl_x509_parse_impl(asn1der, cert_out, &parsed_len));
      81                 :            : 
      82                 :            :     /* Some TLS clients in the wild send extra trailing bytes after the Certificate.
      83                 :            :      * Allow this in s2n for backwards compatibility with existing clients. */
      84                 :       5982 :     uint32_t trailing_bytes = asn1der->size - parsed_len;
      85 [ +  - ][ +  + ]:       5982 :     RESULT_ENSURE(trailing_bytes <= S2N_MAX_ALLOWED_CERT_TRAILING_BYTES, S2N_ERR_DECODE_CERTIFICATE);
      86                 :            : 
      87                 :       5980 :     return S2N_RESULT_OK;
      88                 :       5982 : }
      89                 :            : 
      90                 :            : S2N_RESULT s2n_openssl_x509_get_cert_info(X509 *cert, struct s2n_cert_info *info)
      91                 :       2094 : {
      92 [ #  # ][ -  + ]:       2094 :     RESULT_ENSURE_REF(cert);
      93 [ #  # ][ -  + ]:       2094 :     RESULT_ENSURE_REF(info);
      94                 :            : 
      95                 :       2094 :     X509_NAME *issuer_name = X509_get_issuer_name(cert);
      96 [ #  # ][ -  + ]:       2094 :     RESULT_ENSURE_REF(issuer_name);
      97                 :            : 
      98                 :       2094 :     X509_NAME *subject_name = X509_get_subject_name(cert);
      99 [ #  # ][ -  + ]:       2094 :     RESULT_ENSURE_REF(subject_name);
     100                 :            : 
     101         [ +  + ]:       2094 :     if (X509_NAME_cmp(issuer_name, subject_name) == 0) {
     102                 :        986 :         info->self_signed = true;
     103                 :       1108 :     } else {
     104                 :       1108 :         info->self_signed = false;
     105                 :       1108 :     }
     106                 :            : 
     107                 :            : #if defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER < 0x02070000f)
     108                 :            :     RESULT_ENSURE_REF(cert->sig_alg);
     109                 :            :     info->signature_nid = OBJ_obj2nid(cert->sig_alg->algorithm);
     110                 :            : #else
     111                 :       2094 :     info->signature_nid = X509_get_signature_nid(cert);
     112                 :       2094 : #endif
     113                 :            : 
     114                 :            :     /* There is no method to directly retrieve the signature digest from the X509*
     115                 :            :      * that is available in all libcryptos, so instead we use find_sigid_algs. For
     116                 :            :      * a signature with NID_ecdsa_with_SHA256 this will return NID_SHA256
     117                 :            :      *
     118                 :            :      * signature_digest_nid may not always be set. ML-DSA does not have an associated digest.
     119                 :            :      */
     120                 :       2094 :     int find_result = OBJ_find_sigid_algs(info->signature_nid, &info->signature_digest_nid, NULL);
     121         [ -  + ]:       2094 :     if (find_result != 1) {
     122                 :            :         /* OBJ_find_sigid_algs may fail for ML-DSA-44 and ML-DSA-87, depending on the
     123                 :            :          * version of AWS-LC. See https://github.com/aws/aws-lc/issues/2347.
     124                 :            :          *
     125                 :            :          * In order to handle this bug, we interpret failures from OBJ_find_sigid_algs
     126                 :            :          * as signature_digest_nid==0, which is equivalent to an undefined digest.
     127                 :            :          */
     128                 :          0 :         info->signature_digest_nid = 0;
     129                 :          0 :     }
     130                 :            : 
     131                 :       2094 :     DEFER_CLEANUP(EVP_PKEY *pubkey = X509_get_pubkey(cert), EVP_PKEY_free_pointer);
     132 [ -  + ][ #  # ]:       2094 :     RESULT_ENSURE(pubkey != NULL, S2N_ERR_DECODE_CERTIFICATE);
     133                 :            : 
     134                 :       2094 :     info->public_key_bits = EVP_PKEY_bits(pubkey);
     135 [ -  + ][ #  # ]:       2094 :     RESULT_ENSURE(info->public_key_bits > 0, S2N_ERR_CERT_TYPE_UNSUPPORTED);
     136                 :            : 
     137         [ +  + ]:       2094 :     if (EVP_PKEY_base_id(pubkey) == EVP_PKEY_EC) {
     138                 :        269 :         DEFER_CLEANUP(EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(pubkey), EC_KEY_free_pointer);
     139 [ #  # ][ -  + ]:        269 :         RESULT_ENSURE_REF(ec_key);
     140                 :        269 :         const EC_GROUP *ec_group = EC_KEY_get0_group(ec_key);
     141 [ -  + ][ #  # ]:        269 :         RESULT_ENSURE_REF(ec_group);
     142                 :        269 :         info->public_key_nid = EC_GROUP_get_curve_name(ec_group);
     143                 :       1825 :     } else {
     144                 :       1825 :         info->public_key_nid = EVP_PKEY_id(pubkey);
     145                 :       1825 :     }
     146 [ -  + ][ #  # ]:       2094 :     RESULT_ENSURE(info->public_key_nid != NID_undef, S2N_ERR_CERT_TYPE_UNSUPPORTED);
     147                 :            : 
     148                 :       2094 :     return S2N_RESULT_OK;
     149                 :       2094 : }

Generated by: LCOV version 1.14