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