Coverage Report

Created: 2026-07-16 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssl/crypto/pem/pem_info.c
Line
Count
Source
1
/*
2
 * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
3
 *
4
 * Licensed under the Apache License 2.0 (the "License").  You may not use
5
 * this file except in compliance with the License.  You can obtain a copy
6
 * in the file LICENSE in the source distribution or at
7
 * https://www.openssl.org/source/license.html
8
 */
9
10
/*
11
 * DSA low level APIs are deprecated for public use, but still ok for
12
 * internal use.
13
 */
14
#include "internal/deprecated.h"
15
16
#include <stdio.h>
17
#include "internal/cryptlib.h"
18
#include <openssl/buffer.h>
19
#include <openssl/objects.h>
20
#include <openssl/evp.h>
21
#include <openssl/x509.h>
22
#include <openssl/pem.h>
23
#include <openssl/rsa.h>
24
#include <openssl/dsa.h>
25
#include "crypto/evp.h"
26
27
typedef enum {
28
    PEM_INFO_NONE,
29
    PEM_INFO_X509,
30
    PEM_INFO_X509_AUX,
31
    PEM_INFO_X509_CRL,
32
    PEM_INFO_PKEY
33
} pem_info_type;
34
35
#ifndef OPENSSL_NO_STDIO
36
STACK_OF(X509_INFO)
37
*PEM_X509_INFO_read_ex(FILE *fp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb,
38
    void *u, OSSL_LIB_CTX *libctx, const char *propq)
39
0
{
40
0
    BIO *b;
41
0
    STACK_OF(X509_INFO) *ret;
42
43
0
    if ((b = BIO_new(BIO_s_file())) == NULL) {
44
0
        ERR_raise(ERR_LIB_PEM, ERR_R_BUF_LIB);
45
0
        return 0;
46
0
    }
47
0
    BIO_set_fp(b, fp, BIO_NOCLOSE);
48
0
    ret = PEM_X509_INFO_read_bio_ex(b, sk, cb, u, libctx, propq);
49
0
    BIO_free(b);
50
0
    return ret;
51
0
}
52
53
STACK_OF(X509_INFO) *PEM_X509_INFO_read(FILE *fp, STACK_OF(X509_INFO) *sk,
54
    pem_password_cb *cb, void *u)
55
0
{
56
0
    return PEM_X509_INFO_read_ex(fp, sk, cb, u, NULL, NULL);
57
0
}
58
#endif
59
60
STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio_ex(BIO *bp, STACK_OF(X509_INFO) *sk,
61
    pem_password_cb *cb, void *u,
62
    OSSL_LIB_CTX *libctx,
63
    const char *propq)
64
0
{
65
0
    X509_INFO *xi = NULL;
66
0
    char *name = NULL, *header = NULL, *str;
67
0
    void *pp;
68
0
    unsigned char *data = NULL;
69
0
    const unsigned char *p;
70
0
    long len, error = 0;
71
0
    int ok = 0;
72
0
    STACK_OF(X509_INFO) *ret = NULL;
73
0
    unsigned int i, raw, ptype;
74
0
    pem_info_type itype = PEM_INFO_NONE;
75
76
0
    if (sk == NULL) {
77
0
        if ((ret = sk_X509_INFO_new_null()) == NULL) {
78
0
            ERR_raise(ERR_LIB_PEM, ERR_R_CRYPTO_LIB);
79
0
            goto err;
80
0
        }
81
0
    } else
82
0
        ret = sk;
83
84
0
    if ((xi = X509_INFO_new()) == NULL)
85
0
        goto err;
86
0
    for (;;) {
87
0
        raw = 0;
88
0
        ptype = 0;
89
0
        itype = PEM_INFO_NONE;
90
0
        ERR_set_mark();
91
0
        i = PEM_read_bio(bp, &name, &header, &data, &len);
92
0
        if (i == 0) {
93
0
            error = ERR_GET_REASON(ERR_peek_last_error());
94
0
            if (error == PEM_R_NO_START_LINE) {
95
0
                ERR_pop_to_mark();
96
0
                break;
97
0
            }
98
0
            ERR_clear_last_mark();
99
0
            goto err;
100
0
        }
101
0
        ERR_clear_last_mark();
102
0
    start:
103
0
        if (strcmp(name, PEM_STRING_X509) == 0
104
0
            || strcmp(name, PEM_STRING_X509_OLD) == 0
105
0
            || strcmp(name, PEM_STRING_X509_TRUSTED) == 0) {
106
0
            if (xi->x509 != NULL) {
107
0
                if (!sk_X509_INFO_push(ret, xi))
108
0
                    goto err;
109
0
                if ((xi = X509_INFO_new()) == NULL)
110
0
                    goto err;
111
0
                goto start;
112
0
            }
113
0
            if ((strcmp(name, PEM_STRING_X509_TRUSTED) == 0))
114
0
                itype = PEM_INFO_X509_AUX;
115
0
            else
116
0
                itype = PEM_INFO_X509;
117
0
            xi->x509 = X509_new_ex(libctx, propq);
118
0
            if (xi->x509 == NULL)
119
0
                goto err;
120
0
            pp = &(xi->x509);
121
0
        } else if (strcmp(name, PEM_STRING_X509_CRL) == 0) {
122
0
            itype = PEM_INFO_X509_CRL;
123
0
            if (xi->crl != NULL) {
124
0
                if (!sk_X509_INFO_push(ret, xi))
125
0
                    goto err;
126
0
                if ((xi = X509_INFO_new()) == NULL)
127
0
                    goto err;
128
0
                goto start;
129
0
            }
130
0
            pp = &(xi->crl);
131
0
        } else if ((str = strstr(name, PEM_STRING_PKCS8INF)) != NULL) {
132
0
            if (xi->x_pkey != NULL) {
133
0
                if (!sk_X509_INFO_push(ret, xi))
134
0
                    goto err;
135
0
                if ((xi = X509_INFO_new()) == NULL)
136
0
                    goto err;
137
0
                goto start;
138
0
            }
139
0
            if (str == name || strcmp(name, PEM_STRING_PKCS8) == 0) {
140
0
                ptype = EVP_PKEY_NONE;
141
0
            } else {
142
                /* chop " PRIVATE KEY" */
143
0
                *--str = '\0';
144
0
                ptype = evp_pkey_name2type(name);
145
0
            }
146
0
            xi->enc_data = NULL;
147
0
            xi->enc_len = 0;
148
149
0
            itype = PEM_INFO_PKEY;
150
0
            xi->x_pkey = X509_PKEY_new();
151
0
            if (xi->x_pkey == NULL)
152
0
                goto err;
153
0
            pp = &xi->x_pkey->dec_pkey;
154
0
            if ((int)strlen(header) > 10 /* assume encrypted */
155
0
                || strcmp(name, PEM_STRING_PKCS8) == 0)
156
0
                raw = 1;
157
0
        } else { /* unknown */
158
0
            itype = PEM_INFO_NONE;
159
0
            pp = NULL;
160
0
        }
161
162
0
        if (itype != PEM_INFO_NONE) {
163
0
            if (!raw) {
164
0
                EVP_CIPHER_INFO cipher;
165
166
0
                if (!PEM_get_EVP_CIPHER_INFO(header, &cipher))
167
0
                    goto err;
168
0
                if (!PEM_do_header(&cipher, data, &len, cb, u))
169
0
                    goto err;
170
0
                p = data;
171
0
                if (ptype) {
172
0
                    if (d2i_PrivateKey_ex(ptype, (EVP_PKEY **)pp, &p, len,
173
0
                            libctx, propq)
174
0
                        == NULL) {
175
0
                        ERR_raise(ERR_LIB_PEM, ERR_R_ASN1_LIB);
176
0
                        goto err;
177
0
                    }
178
0
                } else {
179
0
                    void *decoded = NULL;
180
181
0
                    switch (itype) {
182
0
                    case PEM_INFO_X509:
183
0
                        decoded = d2i_X509((X509 **)pp, &p, len);
184
0
                        break;
185
0
                    case PEM_INFO_X509_AUX:
186
0
                        decoded = d2i_X509_AUX((X509 **)pp, &p, len);
187
0
                        break;
188
0
                    case PEM_INFO_X509_CRL:
189
0
                        decoded = d2i_X509_CRL((X509_CRL **)pp, &p, len);
190
0
                        break;
191
0
                    case PEM_INFO_PKEY:
192
0
                        decoded = d2i_AutoPrivateKey_ex((EVP_PKEY **)pp, &p,
193
0
                            len, libctx, propq);
194
0
                        break;
195
0
                    default:
196
0
                        break;
197
0
                    }
198
0
                    if (decoded == NULL) {
199
0
                        ERR_raise(ERR_LIB_PEM, ERR_R_ASN1_LIB);
200
0
                        goto err;
201
0
                    }
202
0
                }
203
0
            } else { /* encrypted key data */
204
0
                if (!PEM_get_EVP_CIPHER_INFO(header, &xi->enc_cipher))
205
0
                    goto err;
206
0
                xi->enc_data = (char *)data;
207
0
                xi->enc_len = (int)len;
208
0
                data = NULL;
209
0
            }
210
0
        }
211
0
        OPENSSL_free(name);
212
0
        name = NULL;
213
0
        OPENSSL_free(header);
214
0
        header = NULL;
215
0
        OPENSSL_free(data);
216
0
        data = NULL;
217
0
    }
218
219
    /*
220
     * if the last one hasn't been pushed yet and there is anything in it
221
     * then add it to the stack ...
222
     */
223
0
    if ((xi->x509 != NULL) || (xi->crl != NULL) || (xi->x_pkey != NULL) || (xi->enc_data != NULL)) {
224
0
        if (!sk_X509_INFO_push(ret, xi))
225
0
            goto err;
226
0
        xi = NULL;
227
0
    }
228
0
    ok = 1;
229
0
err:
230
0
    X509_INFO_free(xi);
231
0
    if (!ok) {
232
0
        for (i = 0; ((int)i) < sk_X509_INFO_num(ret); i++) {
233
0
            xi = sk_X509_INFO_value(ret, i);
234
0
            X509_INFO_free(xi);
235
0
        }
236
0
        if (ret != sk)
237
0
            sk_X509_INFO_free(ret);
238
0
        ret = NULL;
239
0
    }
240
241
0
    OPENSSL_free(name);
242
0
    OPENSSL_free(header);
243
0
    OPENSSL_free(data);
244
0
    return ret;
245
0
}
246
247
STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk,
248
    pem_password_cb *cb, void *u)
249
0
{
250
0
    return PEM_X509_INFO_read_bio_ex(bp, sk, cb, u, NULL, NULL);
251
0
}
252
253
/* A TJH addition */
254
int PEM_X509_INFO_write_bio(BIO *bp, const X509_INFO *xi, EVP_CIPHER *enc,
255
    const unsigned char *kstr, int klen,
256
    pem_password_cb *cb, void *u)
257
0
{
258
0
    int i, ret = 0;
259
0
    unsigned char *data = NULL;
260
0
    const char *objstr = NULL;
261
0
    char buf[PEM_BUFSIZE];
262
0
    const unsigned char *iv = NULL;
263
264
0
    if (enc != NULL) {
265
0
        objstr = EVP_CIPHER_get0_name(enc);
266
0
        if (objstr == NULL
267
            /*
268
             * Check "Proc-Type: 4,Encrypted\nDEK-Info: objstr,hex-iv\n"
269
             * fits into buf
270
             */
271
0
            || strlen(objstr) + 23 + 2 * EVP_CIPHER_get_iv_length(enc) + 13
272
0
                > sizeof(buf)) {
273
0
            ERR_raise(ERR_LIB_PEM, PEM_R_UNSUPPORTED_CIPHER);
274
0
            goto err;
275
0
        }
276
0
    }
277
278
    /*
279
     * now for the fun part ... if we have a private key then we have to be
280
     * able to handle a not-yet-decrypted key being written out correctly ...
281
     * if it is decrypted or it is non-encrypted then we use the base code
282
     */
283
0
    if (xi->x_pkey != NULL) {
284
0
        if ((xi->enc_data != NULL) && (xi->enc_len > 0)) {
285
0
            if (enc == NULL) {
286
0
                ERR_raise(ERR_LIB_PEM, PEM_R_CIPHER_IS_NULL);
287
0
                goto err;
288
0
            }
289
290
            /* copy from weirdo names into more normal things */
291
0
            iv = xi->enc_cipher.iv;
292
0
            data = (unsigned char *)xi->enc_data;
293
0
            i = xi->enc_len;
294
295
            /*
296
             * we take the encryption data from the internal stuff rather
297
             * than what the user has passed us ... as we have to match
298
             * exactly for some strange reason
299
             */
300
0
            objstr = EVP_CIPHER_get0_name(xi->enc_cipher.cipher);
301
0
            if (objstr == NULL) {
302
0
                ERR_raise(ERR_LIB_PEM, PEM_R_UNSUPPORTED_CIPHER);
303
0
                goto err;
304
0
            }
305
306
            /* Create the right magic header stuff */
307
0
            buf[0] = '\0';
308
0
            PEM_proc_type(buf, PEM_TYPE_ENCRYPTED);
309
0
            PEM_dek_info(buf, objstr, EVP_CIPHER_get_iv_length(enc),
310
0
                (const char *)iv);
311
312
            /* use the normal code to write things out */
313
0
            i = PEM_write_bio(bp, PEM_STRING_RSA, buf, data, i);
314
0
            if (i <= 0)
315
0
                goto err;
316
0
        } else {
317
            /* Add DSA/DH */
318
            /* normal optionally encrypted stuff */
319
0
            if (PEM_write_bio_RSAPrivateKey(bp,
320
0
                    EVP_PKEY_get0_RSA(xi->x_pkey->dec_pkey),
321
0
                    enc, kstr, klen, cb, u)
322
0
                <= 0)
323
0
                goto err;
324
0
        }
325
0
    }
326
327
    /* if we have a certificate then write it out now */
328
0
    if ((xi->x509 != NULL) && (PEM_write_bio_X509(bp, xi->x509) <= 0))
329
0
        goto err;
330
331
    /*
332
     * we are ignoring anything else that is loaded into the X509_INFO
333
     * structure for the moment ... as I don't need it so I'm not coding it
334
     * here and Eric can do it when this makes it into the base library --tjh
335
     */
336
337
0
    ret = 1;
338
339
0
err:
340
0
    OPENSSL_cleanse(buf, PEM_BUFSIZE);
341
0
    return ret;
342
0
}