Coverage Report

Created: 2026-04-02 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/pem/pem_info.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/pem.h>
16
17
#include <limits.h>
18
#include <string.h>
19
20
#include <string_view>
21
22
#include <openssl/dsa.h>
23
#include <openssl/err.h>
24
#include <openssl/evp.h>
25
#include <openssl/mem.h>
26
#include <openssl/obj.h>
27
#include <openssl/rsa.h>
28
#include <openssl/x509.h>
29
30
#include "../mem_internal.h"
31
#include "internal.h"
32
33
34
using namespace bssl;
35
36
0
static X509_PKEY *X509_PKEY_new() { return New<X509_PKEY>(); }
37
38
0
static void X509_PKEY_free(X509_PKEY *x) {
39
0
  if (x == nullptr) {
40
0
    return;
41
0
  }
42
43
0
  EVP_PKEY_free(x->dec_pkey);
44
0
  Delete(x);
45
0
}
46
47
0
static X509_INFO *X509_INFO_new() { return New<X509_INFO>(); }
48
49
0
void X509_INFO_free(X509_INFO *x) {
50
0
  if (x == nullptr) {
51
0
    return;
52
0
  }
53
54
0
  X509_free(x->x509);
55
0
  X509_CRL_free(x->crl);
56
0
  X509_PKEY_free(x->x_pkey);
57
0
  OPENSSL_free(x->enc_data);
58
0
  Delete(x);
59
0
}
60
61
62
STACK_OF(X509_INFO) *PEM_X509_INFO_read(FILE *fp, STACK_OF(X509_INFO) *sk,
63
0
                                        pem_password_cb *cb, void *u) {
64
0
  BIO *b = BIO_new_fp(fp, BIO_NOCLOSE);
65
0
  if (b == nullptr) {
66
0
    OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB);
67
0
    return nullptr;
68
0
  }
69
0
  STACK_OF(X509_INFO) *ret = PEM_X509_INFO_read_bio(b, sk, cb, u);
70
0
  BIO_free(b);
71
0
  return ret;
72
0
}
73
74
enum parse_result_t {
75
  parse_ok,
76
  parse_error,
77
  parse_new_entry,
78
};
79
80
static enum parse_result_t parse_x509(X509_INFO *info, const uint8_t *data,
81
0
                                      size_t len, int key_type) {
82
0
  if (info->x509 != nullptr) {
83
0
    return parse_new_entry;
84
0
  }
85
0
  info->x509 = d2i_X509(nullptr, &data, len);
86
0
  return info->x509 != nullptr ? parse_ok : parse_error;
87
0
}
88
89
static enum parse_result_t parse_x509_aux(X509_INFO *info, const uint8_t *data,
90
0
                                          size_t len, int key_type) {
91
0
  if (info->x509 != nullptr) {
92
0
    return parse_new_entry;
93
0
  }
94
0
  info->x509 = d2i_X509_AUX(nullptr, &data, len);
95
0
  return info->x509 != nullptr ? parse_ok : parse_error;
96
0
}
97
98
static enum parse_result_t parse_crl(X509_INFO *info, const uint8_t *data,
99
0
                                     size_t len, int key_type) {
100
0
  if (info->crl != nullptr) {
101
0
    return parse_new_entry;
102
0
  }
103
0
  info->crl = d2i_X509_CRL(nullptr, &data, len);
104
0
  return info->crl != nullptr ? parse_ok : parse_error;
105
0
}
106
107
static enum parse_result_t parse_key(X509_INFO *info, const uint8_t *data,
108
0
                                     size_t len, int key_type) {
109
0
  if (info->x_pkey != nullptr) {
110
0
    return parse_new_entry;
111
0
  }
112
0
  info->x_pkey = X509_PKEY_new();
113
0
  if (info->x_pkey == nullptr) {
114
0
    return parse_error;
115
0
  }
116
0
  info->x_pkey->dec_pkey = d2i_PrivateKey(key_type, nullptr, &data, len);
117
0
  return info->x_pkey->dec_pkey != nullptr ? parse_ok : parse_error;
118
0
}
119
120
STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk,
121
0
                                            pem_password_cb *cb, void *u) {
122
0
  X509_INFO *info = nullptr;
123
0
  UniquePtr<char> name;
124
0
  UniquePtr<char> header;
125
0
  Array<uint8_t> data;
126
0
  int ok = 0;
127
0
  STACK_OF(X509_INFO) *ret = nullptr;
128
129
0
  if (sk == nullptr) {
130
0
    ret = sk_X509_INFO_new_null();
131
0
    if (ret == nullptr) {
132
0
      return nullptr;
133
0
    }
134
0
  } else {
135
0
    ret = sk;
136
0
  }
137
0
  size_t orig_num = sk_X509_INFO_num(ret);
138
139
0
  info = X509_INFO_new();
140
0
  if (info == nullptr) {
141
0
    goto err;
142
0
  }
143
144
0
  for (;;) {
145
0
    if (!PEM_read_bio_inner(bp, &name, &header, &data)) {
146
0
      if (ERR_equals(ERR_peek_last_error(), ERR_LIB_PEM, PEM_R_NO_START_LINE)) {
147
0
        ERR_clear_error();
148
0
        break;
149
0
      }
150
0
      goto err;
151
0
    }
152
153
0
    enum parse_result_t (*parse_function)(X509_INFO *, const uint8_t *, size_t,
154
0
                                          int) = nullptr;
155
0
    int key_type = EVP_PKEY_NONE;
156
0
    std::string_view name_view = name.get();
157
0
    if (name_view == PEM_STRING_X509 || name_view == PEM_STRING_X509_OLD) {
158
0
      parse_function = parse_x509;
159
0
    } else if (name_view == PEM_STRING_X509_TRUSTED) {
160
0
      parse_function = parse_x509_aux;
161
0
    } else if (name_view == PEM_STRING_X509_CRL) {
162
0
      parse_function = parse_crl;
163
0
    } else if (name_view == PEM_STRING_RSA) {
164
0
      parse_function = parse_key;
165
0
      key_type = EVP_PKEY_RSA;
166
0
    } else if (name_view == PEM_STRING_DSA) {
167
0
      parse_function = parse_key;
168
0
      key_type = EVP_PKEY_DSA;
169
0
    } else if (name_view == PEM_STRING_ECPRIVATEKEY) {
170
0
      parse_function = parse_key;
171
0
      key_type = EVP_PKEY_EC;
172
0
    }
173
174
    // If a private key has a header, assume it is encrypted. This function does
175
    // not decrypt private keys.
176
0
    if (key_type != EVP_PKEY_NONE && strlen(header.get()) > 10) {
177
0
      if (data.size() > INT_MAX) {
178
        // We need the data to fit in |info| which forces the size to
179
        // fit in one int type.
180
0
        goto err;
181
0
      }
182
0
      if (info->x_pkey != nullptr) {
183
0
        if (!sk_X509_INFO_push(ret, info)) {
184
0
          goto err;
185
0
        }
186
0
        info = X509_INFO_new();
187
0
        if (info == nullptr) {
188
0
          goto err;
189
0
        }
190
0
      }
191
      // Use an empty key as a placeholder.
192
0
      info->x_pkey = X509_PKEY_new();
193
0
      if (info->x_pkey == nullptr ||
194
0
          !PEM_get_EVP_CIPHER_INFO(header.get(), &info->enc_cipher)) {
195
0
        goto err;
196
0
      }
197
0
      size_t size;
198
0
      data.Release(reinterpret_cast<uint8_t **>(&info->enc_data), &size);
199
      // Safety: we checked that |size| <= |INT_MAX|.
200
0
      info->enc_len = static_cast<int>(size);
201
0
    } else if (parse_function != nullptr) {
202
0
      EVP_CIPHER_INFO cipher;
203
0
      size_t len = data.size();
204
0
      if (!PEM_get_EVP_CIPHER_INFO(header.get(), &cipher) ||
205
0
          !PEM_do_header(&cipher, data.data(), &len, cb, u)) {
206
0
        goto err;
207
0
      }
208
0
      enum parse_result_t result =
209
0
          parse_function(info, data.data(), len, key_type);
210
0
      if (result == parse_new_entry) {
211
0
        if (!sk_X509_INFO_push(ret, info)) {
212
0
          goto err;
213
0
        }
214
0
        info = X509_INFO_new();
215
0
        if (info == nullptr) {
216
0
          goto err;
217
0
        }
218
0
        result = parse_function(info, data.data(), len, key_type);
219
0
      }
220
0
      if (result != parse_ok) {
221
0
        OPENSSL_PUT_ERROR(PEM, ERR_R_ASN1_LIB);
222
0
        goto err;
223
0
      }
224
0
    }
225
0
  }
226
227
  // Push the last entry on the stack if not empty.
228
0
  if (info->x509 != nullptr || info->crl != nullptr ||
229
0
      info->x_pkey != nullptr || info->enc_data != nullptr) {
230
0
    if (!sk_X509_INFO_push(ret, info)) {
231
0
      goto err;
232
0
    }
233
0
    info = nullptr;
234
0
  }
235
236
0
  ok = 1;
237
238
0
err:
239
0
  X509_INFO_free(info);
240
0
  if (!ok) {
241
0
    while (sk_X509_INFO_num(ret) > orig_num) {
242
0
      X509_INFO_free(sk_X509_INFO_pop(ret));
243
0
    }
244
0
    if (ret != sk) {
245
0
      sk_X509_INFO_free(ret);
246
0
    }
247
0
    ret = nullptr;
248
0
  }
249
0
  return ret;
250
0
}