Coverage Report

Created: 2026-06-15 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/x509/x_pubkey.cc
Line
Count
Source
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 <limits.h>
18
19
#include <openssl/asn1.h>
20
#include <openssl/asn1t.h>
21
#include <openssl/bytestring.h>
22
#include <openssl/err.h>
23
#include <openssl/evp.h>
24
#include <openssl/mem.h>
25
#include <openssl/obj.h>
26
#include <openssl/span.h>
27
28
#include "../asn1/internal.h"
29
#include "../bytestring/internal.h"
30
#include "../evp/internal.h"
31
#include "../internal.h"
32
#include "../mem_internal.h"
33
#include "internal.h"
34
35
36
using namespace bssl;
37
38
189k
void bssl::x509_pubkey_init(X509_PUBKEY *key) {
39
189k
  OPENSSL_memset(key, 0, sizeof(X509_PUBKEY));
40
189k
  x509_algor_init(&key->algor);
41
189k
  asn1_string_init(&key->public_key, V_ASN1_BIT_STRING);
42
189k
}
43
44
0
X509_PUBKEY *X509_PUBKEY_new() {
45
0
  UniquePtr<X509_PUBKEY> ret = MakeUnique<X509_PUBKEY>();
46
0
  if (ret == nullptr) {
47
0
    return nullptr;
48
0
  }
49
0
  x509_pubkey_init(ret.get());
50
0
  return ret.release();
51
0
}
52
53
189k
void bssl::x509_pubkey_cleanup(X509_PUBKEY *key) {
54
189k
  x509_algor_cleanup(&key->algor);
55
189k
  asn1_string_cleanup(&key->public_key);
56
189k
  EVP_PKEY_free(key->pkey);
57
189k
}
58
59
0
void X509_PUBKEY_free(X509_PUBKEY *key) {
60
0
  if (key != nullptr) {
61
0
    x509_pubkey_cleanup(key);
62
0
    OPENSSL_free(key);
63
0
  }
64
0
}
65
66
static void x509_pubkey_changed(X509_PUBKEY *pub,
67
178k
                                Span<const EVP_PKEY_ALG *const> algs) {
68
178k
  EVP_PKEY_free(pub->pkey);
69
178k
  pub->pkey = nullptr;
70
71
  // Re-encode the `X509_PUBKEY` to DER and parse it with EVP's APIs. If the
72
  // operation fails, clear errors. An `X509_PUBKEY` whose key we cannot parse
73
  // is still a valid SPKI. It just cannot be converted to an `EVP_PKEY`.
74
178k
  ScopedCBB cbb;
75
178k
  if (!CBB_init(cbb.get(), 64) || !x509_marshal_public_key(cbb.get(), pub)) {
76
0
    ERR_clear_error();
77
0
    return;
78
0
  }
79
178k
  UniquePtr<EVP_PKEY> pkey(EVP_PKEY_from_subject_public_key_info(
80
178k
      CBB_data(cbb.get()), CBB_len(cbb.get()), algs.data(), algs.size()));
81
178k
  if (pkey == nullptr) {
82
86.4k
    ERR_clear_error();
83
86.4k
    return;
84
86.4k
  }
85
86
92.0k
  pub->pkey = pkey.release();
87
92.0k
}
88
89
int bssl::x509_parse_public_key(CBS *cbs, X509_PUBKEY *out,
90
178k
                                Span<const EVP_PKEY_ALG *const> algs) {
91
178k
  CBS seq;
92
178k
  if (!CBS_get_asn1(cbs, &seq, CBS_ASN1_SEQUENCE) ||
93
178k
      !x509_parse_algorithm(&seq, &out->algor) ||
94
178k
      !asn1_parse_bit_string(&seq, &out->public_key, /*tag=*/0) ||
95
178k
      CBS_len(&seq) != 0) {
96
500
    OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR);
97
500
    return 0;
98
500
  }
99
178k
  x509_pubkey_changed(out, algs);
100
178k
  return 1;
101
178k
}
102
103
0
static int x509_parse_public_key_default(CBS *cbs, X509_PUBKEY *out) {
104
0
  return x509_parse_public_key(cbs, out, GetDefaultEVPAlgorithms());
105
0
}
106
107
181k
int bssl::x509_marshal_public_key(CBB *cbb, const X509_PUBKEY *in) {
108
181k
  CBB seq;
109
181k
  return CBB_add_asn1(cbb, &seq, CBS_ASN1_SEQUENCE) &&
110
181k
         x509_marshal_algorithm(&seq, &in->algor) &&
111
181k
         asn1_marshal_bit_string(&seq, &in->public_key, /*tag=*/0) &&
112
181k
         CBB_flush(cbb);
113
181k
}
114
115
0
X509_PUBKEY *d2i_X509_PUBKEY(X509_PUBKEY **out, const uint8_t **inp, long len) {
116
0
  return D2IFromCBS(out, inp, len, [](CBS *cbs) -> UniquePtr<X509_PUBKEY> {
117
0
    UniquePtr<X509_PUBKEY> ret(X509_PUBKEY_new());
118
0
    if (ret == nullptr || !x509_parse_public_key_default(cbs, ret.get())) {
119
0
      return nullptr;
120
0
    }
121
0
    return ret;
122
0
  });
123
0
}
124
125
0
int i2d_X509_PUBKEY(const X509_PUBKEY *key, uint8_t **outp) {
126
0
  return I2DFromCBB(/*initial_capacity=*/32, outp, [&](CBB *cbb) -> bool {
127
0
    return x509_marshal_public_key(cbb, key);
128
0
  });
129
0
}
130
131
BSSL_NAMESPACE_BEGIN
132
133
// TODO(crbug.com/42290417): Remove this when `X509` and `X509_REQ` no longer
134
// depend on the tables.
135
IMPLEMENT_EXTERN_ASN1_SIMPLE(X509_PUBKEY, X509_PUBKEY_new, X509_PUBKEY_free,
136
                             CBS_ASN1_SEQUENCE, x509_parse_public_key_default,
137
                             i2d_X509_PUBKEY)
138
139
BSSL_NAMESPACE_END
140
141
0
int bssl::x509_pubkey_set1(X509_PUBKEY *key, EVP_PKEY *pkey) {
142
0
  ScopedCBB cbb;
143
0
  if (!CBB_init(cbb.get(), 64) || !EVP_marshal_public_key(cbb.get(), pkey)) {
144
0
    OPENSSL_PUT_ERROR(X509, X509_R_PUBLIC_KEY_ENCODE_ERROR);
145
0
    return 0;
146
0
  }
147
148
0
  CBS cbs;
149
0
  CBS_init(&cbs, CBB_data(cbb.get()), CBB_len(cbb.get()));
150
  // TODO(crbug.com/42290364): Use an `EVP_PKEY_ALG` derived from `pkey`.
151
  // `X509_PUBKEY_get0` does not currently work when setting, say, an
152
  // `EVP_PKEY_RSA_PSS` key.
153
0
  return x509_parse_public_key(&cbs, key, GetDefaultEVPAlgorithms());
154
0
}
155
156
0
int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey) {
157
0
  UniquePtr<X509_PUBKEY> new_key(X509_PUBKEY_new());
158
0
  if (new_key == nullptr || !x509_pubkey_set1(new_key.get(), pkey)) {
159
0
    return 0;
160
0
  }
161
0
  X509_PUBKEY_free(*x);
162
0
  *x = new_key.release();
163
0
  return 1;
164
0
}
165
166
8.44k
EVP_PKEY *X509_PUBKEY_get0(const X509_PUBKEY *key) {
167
8.44k
  if (key == nullptr) {
168
0
    return nullptr;
169
0
  }
170
171
8.44k
  if (key->pkey == nullptr) {
172
6.88k
    OPENSSL_PUT_ERROR(X509, X509_R_PUBLIC_KEY_DECODE_ERROR);
173
6.88k
    return nullptr;
174
6.88k
  }
175
176
1.55k
  return key->pkey;
177
8.44k
}
178
179
5.26k
EVP_PKEY *X509_PUBKEY_get(const X509_PUBKEY *key) {
180
5.26k
  EVP_PKEY *pkey = X509_PUBKEY_get0(key);
181
5.26k
  if (pkey != nullptr) {
182
1.03k
    EVP_PKEY_up_ref(pkey);
183
1.03k
  }
184
5.26k
  return pkey;
185
5.26k
}
186
187
int X509_PUBKEY_set0_param(X509_PUBKEY *pub, ASN1_OBJECT *obj, int param_type,
188
0
                           void *param_value, uint8_t *key, int key_len) {
189
0
  if (!X509_ALGOR_set0(&pub->algor, obj, param_type, param_value)) {
190
0
    return 0;
191
0
  }
192
193
0
  ASN1_STRING_set0(&pub->public_key, key, key_len);
194
0
  x509_pubkey_changed(pub, GetDefaultEVPAlgorithms());
195
0
  return 1;
196
0
}
197
198
int X509_PUBKEY_get0_param(ASN1_OBJECT **out_obj, const uint8_t **out_key,
199
                           int *out_key_len, X509_ALGOR **out_alg,
200
0
                           X509_PUBKEY *pub) {
201
0
  if (out_obj != nullptr) {
202
0
    *out_obj = pub->algor.algorithm;
203
0
  }
204
0
  if (out_key != nullptr) {
205
0
    *out_key = pub->public_key.data;
206
0
    *out_key_len = pub->public_key.length;
207
0
  }
208
0
  if (out_alg != nullptr) {
209
0
    *out_alg = &pub->algor;
210
0
  }
211
0
  return 1;
212
0
}
213
214
0
const ASN1_BIT_STRING *X509_PUBKEY_get0_public_key(const X509_PUBKEY *pub) {
215
0
  return &pub->public_key;
216
0
}