Coverage Report

Created: 2025-08-28 06:59

/src/boringssl/crypto/x509/algorithm.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#include <openssl/x509.h>
16
17
#include <openssl/asn1.h>
18
#include <openssl/digest.h>
19
#include <openssl/err.h>
20
#include <openssl/evp.h>
21
#include <openssl/obj.h>
22
23
#include "internal.h"
24
25
// Restrict the digests that are allowed in X509 certificates
26
0
static int x509_digest_nid_ok(const int digest_nid) {
27
0
  switch (digest_nid) {
28
0
    case NID_md4:
29
0
    case NID_md5:
30
0
      return 0;
31
0
  }
32
0
  return 1;
33
0
}
34
35
0
int x509_digest_sign_algorithm(EVP_MD_CTX *ctx, X509_ALGOR *algor) {
36
0
  EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx->pctx);
37
0
  if (pkey == NULL) {
38
0
    OPENSSL_PUT_ERROR(ASN1, ASN1_R_CONTEXT_NOT_INITIALISED);
39
0
    return 0;
40
0
  }
41
42
0
  if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA) {
43
0
    int pad_mode;
44
0
    if (!EVP_PKEY_CTX_get_rsa_padding(ctx->pctx, &pad_mode)) {
45
0
      return 0;
46
0
    }
47
    // RSA-PSS has special signature algorithm logic.
48
0
    if (pad_mode == RSA_PKCS1_PSS_PADDING) {
49
0
      return x509_rsa_ctx_to_pss(ctx, algor);
50
0
    }
51
0
  }
52
53
0
  if (EVP_PKEY_id(pkey) == EVP_PKEY_ED25519) {
54
0
    return X509_ALGOR_set0(algor, OBJ_nid2obj(NID_ED25519), V_ASN1_UNDEF, NULL);
55
0
  }
56
57
  // Default behavior: look up the OID for the algorithm/hash pair and encode
58
  // that.
59
0
  const EVP_MD *digest = EVP_MD_CTX_get0_md(ctx);
60
0
  if (digest == NULL) {
61
0
    OPENSSL_PUT_ERROR(ASN1, ASN1_R_CONTEXT_NOT_INITIALISED);
62
0
    return 0;
63
0
  }
64
65
0
  const int digest_nid = EVP_MD_type(digest);
66
0
  int sign_nid;
67
0
  if (!x509_digest_nid_ok(digest_nid) ||
68
0
      !OBJ_find_sigid_by_algs(&sign_nid, digest_nid, EVP_PKEY_id(pkey))) {
69
0
    OPENSSL_PUT_ERROR(ASN1, ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED);
70
0
    return 0;
71
0
  }
72
73
  // RSA signature algorithms include an explicit NULL parameter. Others omit
74
  // it.
75
0
  int paramtype =
76
0
      (EVP_PKEY_id(pkey) == EVP_PKEY_RSA) ? V_ASN1_NULL : V_ASN1_UNDEF;
77
0
  return X509_ALGOR_set0(algor, OBJ_nid2obj(sign_nid), paramtype, NULL);
78
0
}
79
80
int x509_digest_verify_init(EVP_MD_CTX *ctx, const X509_ALGOR *sigalg,
81
0
                            EVP_PKEY *pkey) {
82
  // Convert the signature OID into digest and public key OIDs.
83
0
  int sigalg_nid = OBJ_obj2nid(sigalg->algorithm);
84
0
  int digest_nid, pkey_nid;
85
0
  if (!OBJ_find_sigid_algs(sigalg_nid, &digest_nid, &pkey_nid)) {
86
0
    OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM);
87
0
    return 0;
88
0
  }
89
90
  // Check the public key OID matches the public key type.
91
0
  if (pkey_nid != EVP_PKEY_id(pkey)) {
92
0
    OPENSSL_PUT_ERROR(ASN1, ASN1_R_WRONG_PUBLIC_KEY_TYPE);
93
0
    return 0;
94
0
  }
95
96
  // Check for permitted digest algorithms
97
0
  if (!x509_digest_nid_ok(digest_nid)) {
98
0
    OPENSSL_PUT_ERROR(ASN1, ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED);
99
0
    return 0;
100
0
  }
101
102
  // NID_undef signals that there are custom parameters to set.
103
0
  if (digest_nid == NID_undef) {
104
0
    if (sigalg_nid == NID_rsassaPss) {
105
0
      return x509_rsa_pss_to_ctx(ctx, sigalg, pkey);
106
0
    }
107
0
    if (sigalg_nid == NID_ED25519) {
108
0
      if (sigalg->parameter != NULL) {
109
0
        OPENSSL_PUT_ERROR(X509, X509_R_INVALID_PARAMETER);
110
0
        return 0;
111
0
      }
112
0
      return EVP_DigestVerifyInit(ctx, NULL, NULL, NULL, pkey);
113
0
    }
114
0
    OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM);
115
0
    return 0;
116
0
  }
117
118
  // The parameter should be an explicit NULL for RSA and omitted for ECDSA. For
119
  // compatibility, we allow either for both algorithms. See b/167375496.
120
  //
121
  // TODO(davidben): Chromium's verifier allows both forms for RSA, but enforces
122
  // ECDSA more strictly. Align with Chromium and add a flag for b/167375496.
123
0
  if (sigalg->parameter != NULL && sigalg->parameter->type != V_ASN1_NULL) {
124
0
    OPENSSL_PUT_ERROR(X509, X509_R_INVALID_PARAMETER);
125
0
    return 0;
126
0
  }
127
128
  // Otherwise, initialize with the digest from the OID.
129
0
  const EVP_MD *digest = EVP_get_digestbynid(digest_nid);
130
0
  if (digest == NULL) {
131
0
    OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM);
132
0
    return 0;
133
0
  }
134
135
0
  return EVP_DigestVerifyInit(ctx, NULL, digest, NULL, pkey);
136
0
}