Coverage Report

Created: 2026-08-08 07:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/pem/pem_pkey.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 <stdio.h>
18
#include <string.h>
19
20
#include <openssl/dh.h>
21
#include <openssl/err.h>
22
#include <openssl/evp.h>
23
#include <openssl/mem.h>
24
#include <openssl/obj.h>
25
#include <openssl/pkcs8.h>
26
#include <openssl/rand.h>
27
#include <openssl/x509.h>
28
29
EVP_PKEY *PEM_read_bio_PrivateKey(BIO *bp, EVP_PKEY **x, pem_password_cb *cb,
30
0
                                  void *u) {
31
0
  char *nm = nullptr;
32
0
  const unsigned char *p = nullptr;
33
0
  unsigned char *data = nullptr;
34
0
  long len;
35
0
  EVP_PKEY *ret = nullptr;
36
37
0
  if (!PEM_bytes_read_bio(&data, &len, &nm, PEM_STRING_EVP_PKEY, bp, cb, u)) {
38
0
    return nullptr;
39
0
  }
40
0
  p = data;
41
42
0
  if (strcmp(nm, PEM_STRING_PKCS8INF) == 0) {
43
0
    PKCS8_PRIV_KEY_INFO *p8inf;
44
0
    p8inf = d2i_PKCS8_PRIV_KEY_INFO(nullptr, &p, len);
45
0
    if (!p8inf) {
46
0
      goto p8err;
47
0
    }
48
0
    ret = EVP_PKCS82PKEY(p8inf);
49
0
    if (x) {
50
0
      if (*x) {
51
0
        EVP_PKEY_free((EVP_PKEY *)*x);
52
0
      }
53
0
      *x = ret;
54
0
    }
55
0
    PKCS8_PRIV_KEY_INFO_free(p8inf);
56
0
  } else if (strcmp(nm, PEM_STRING_PKCS8) == 0) {
57
0
    PKCS8_PRIV_KEY_INFO *p8inf;
58
0
    X509_SIG *p8;
59
0
    int pass_len;
60
0
    char psbuf[PEM_BUFSIZE];
61
0
    p8 = d2i_X509_SIG(nullptr, &p, len);
62
0
    if (!p8) {
63
0
      goto p8err;
64
0
    }
65
66
0
    pass_len = 0;
67
0
    if (!cb) {
68
0
      cb = PEM_def_callback;
69
0
    }
70
0
    pass_len = cb(psbuf, PEM_BUFSIZE, /*enc=*/0, u);
71
0
    if (pass_len < 0) {
72
0
      OPENSSL_PUT_ERROR(PEM, PEM_R_BAD_PASSWORD_READ);
73
0
      X509_SIG_free(p8);
74
0
      goto err;
75
0
    }
76
0
    p8inf = PKCS8_decrypt(p8, psbuf, pass_len);
77
0
    X509_SIG_free(p8);
78
0
    OPENSSL_cleanse(psbuf, pass_len);
79
0
    if (!p8inf) {
80
0
      goto p8err;
81
0
    }
82
0
    ret = EVP_PKCS82PKEY(p8inf);
83
0
    if (x) {
84
0
      if (*x) {
85
0
        EVP_PKEY_free(*x);
86
0
      }
87
0
      *x = ret;
88
0
    }
89
0
    PKCS8_PRIV_KEY_INFO_free(p8inf);
90
0
  } else if (strcmp(nm, PEM_STRING_RSA) == 0) {
91
    // TODO(davidben): d2i_PrivateKey parses PKCS#8 along with the
92
    // standalone format. This and the cases below probably should not
93
    // accept PKCS#8.
94
0
    ret = d2i_PrivateKey(EVP_PKEY_RSA, x, &p, len);
95
0
  } else if (strcmp(nm, PEM_STRING_EC) == 0) {
96
0
    ret = d2i_PrivateKey(EVP_PKEY_EC, x, &p, len);
97
0
  } else if (strcmp(nm, PEM_STRING_DSA) == 0) {
98
0
    ret = d2i_PrivateKey(EVP_PKEY_DSA, x, &p, len);
99
0
  } else {
100
    // `PEM_bytes_read_bio` should not have returned a PEM type this function
101
    // does not recognized.
102
0
    OPENSSL_PUT_ERROR(PEM, ERR_R_INTERNAL_ERROR);
103
0
    goto err;
104
0
  }
105
106
0
p8err:
107
0
  if (ret == nullptr) {
108
0
    OPENSSL_PUT_ERROR(PEM, ERR_R_ASN1_LIB);
109
0
  }
110
111
0
err:
112
0
  OPENSSL_free(nm);
113
0
  OPENSSL_free(data);
114
0
  return ret;
115
0
}
116
117
int PEM_write_bio_PrivateKey(BIO *bp, const EVP_PKEY *x, const EVP_CIPHER *enc,
118
                             const unsigned char *pass, int pass_len,
119
0
                             pem_password_cb *cb, void *u) {
120
0
  return PEM_write_bio_PKCS8PrivateKey(bp, x, enc, (const char *)pass, pass_len,
121
0
                                       cb, u);
122
0
}
123
124
EVP_PKEY *PEM_read_PrivateKey(FILE *fp, EVP_PKEY **x, pem_password_cb *cb,
125
0
                              void *u) {
126
0
  BIO *b = BIO_new_fp(fp, BIO_NOCLOSE);
127
0
  if (b == nullptr) {
128
0
    OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB);
129
0
    return nullptr;
130
0
  }
131
0
  EVP_PKEY *ret = PEM_read_bio_PrivateKey(b, x, cb, u);
132
0
  BIO_free(b);
133
0
  return ret;
134
0
}
135
136
int PEM_write_PrivateKey(FILE *fp, const EVP_PKEY *x, const EVP_CIPHER *enc,
137
                         const unsigned char *pass, int pass_len,
138
0
                         pem_password_cb *cb, void *u) {
139
0
  BIO *b = BIO_new_fp(fp, BIO_NOCLOSE);
140
0
  if (b == nullptr) {
141
0
    OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB);
142
0
    return 0;
143
0
  }
144
0
  int ret = PEM_write_bio_PrivateKey(b, x, enc, pass, pass_len, cb, u);
145
0
  BIO_free(b);
146
0
  return ret;
147
0
}