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#include <stdio.h>
11e1051a39Sopenharmony_ci#include "internal/cryptlib.h"
12e1051a39Sopenharmony_ci#include <openssl/buffer.h>
13e1051a39Sopenharmony_ci#include <openssl/bn.h>
14e1051a39Sopenharmony_ci#include <openssl/objects.h>
15e1051a39Sopenharmony_ci#include <openssl/x509.h>
16e1051a39Sopenharmony_ci#include <openssl/x509v3.h>
17e1051a39Sopenharmony_ci#include "crypto/asn1.h"
18e1051a39Sopenharmony_ci#include "crypto/x509.h"
19e1051a39Sopenharmony_ci
20e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_STDIO
21e1051a39Sopenharmony_ciint X509_print_fp(FILE *fp, X509 *x)
22e1051a39Sopenharmony_ci{
23e1051a39Sopenharmony_ci    return X509_print_ex_fp(fp, x, XN_FLAG_COMPAT, X509_FLAG_COMPAT);
24e1051a39Sopenharmony_ci}
25e1051a39Sopenharmony_ci
26e1051a39Sopenharmony_ciint X509_print_ex_fp(FILE *fp, X509 *x, unsigned long nmflag,
27e1051a39Sopenharmony_ci                     unsigned long cflag)
28e1051a39Sopenharmony_ci{
29e1051a39Sopenharmony_ci    BIO *b;
30e1051a39Sopenharmony_ci    int ret;
31e1051a39Sopenharmony_ci
32e1051a39Sopenharmony_ci    if ((b = BIO_new(BIO_s_file())) == NULL) {
33e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_X509, ERR_R_BUF_LIB);
34e1051a39Sopenharmony_ci        return 0;
35e1051a39Sopenharmony_ci    }
36e1051a39Sopenharmony_ci    BIO_set_fp(b, fp, BIO_NOCLOSE);
37e1051a39Sopenharmony_ci    ret = X509_print_ex(b, x, nmflag, cflag);
38e1051a39Sopenharmony_ci    BIO_free(b);
39e1051a39Sopenharmony_ci    return ret;
40e1051a39Sopenharmony_ci}
41e1051a39Sopenharmony_ci#endif
42e1051a39Sopenharmony_ci
43e1051a39Sopenharmony_ciint X509_print(BIO *bp, X509 *x)
44e1051a39Sopenharmony_ci{
45e1051a39Sopenharmony_ci    return X509_print_ex(bp, x, XN_FLAG_COMPAT, X509_FLAG_COMPAT);
46e1051a39Sopenharmony_ci}
47e1051a39Sopenharmony_ci
48e1051a39Sopenharmony_ciint X509_print_ex(BIO *bp, X509 *x, unsigned long nmflags,
49e1051a39Sopenharmony_ci                  unsigned long cflag)
50e1051a39Sopenharmony_ci{
51e1051a39Sopenharmony_ci    long l;
52e1051a39Sopenharmony_ci    int ret = 0, i;
53e1051a39Sopenharmony_ci    char *m = NULL, mlch = ' ';
54e1051a39Sopenharmony_ci    int nmindent = 0, printok = 0;
55e1051a39Sopenharmony_ci    EVP_PKEY *pkey = NULL;
56e1051a39Sopenharmony_ci    const char *neg;
57e1051a39Sopenharmony_ci
58e1051a39Sopenharmony_ci    if ((nmflags & XN_FLAG_SEP_MASK) == XN_FLAG_SEP_MULTILINE) {
59e1051a39Sopenharmony_ci        mlch = '\n';
60e1051a39Sopenharmony_ci        nmindent = 12;
61e1051a39Sopenharmony_ci    }
62e1051a39Sopenharmony_ci
63e1051a39Sopenharmony_ci    if (nmflags == X509_FLAG_COMPAT) {
64e1051a39Sopenharmony_ci        nmindent = 16;
65e1051a39Sopenharmony_ci        printok = 1;
66e1051a39Sopenharmony_ci    }
67e1051a39Sopenharmony_ci
68e1051a39Sopenharmony_ci    if (!(cflag & X509_FLAG_NO_HEADER)) {
69e1051a39Sopenharmony_ci        if (BIO_write(bp, "Certificate:\n", 13) <= 0)
70e1051a39Sopenharmony_ci            goto err;
71e1051a39Sopenharmony_ci        if (BIO_write(bp, "    Data:\n", 10) <= 0)
72e1051a39Sopenharmony_ci            goto err;
73e1051a39Sopenharmony_ci    }
74e1051a39Sopenharmony_ci    if (!(cflag & X509_FLAG_NO_VERSION)) {
75e1051a39Sopenharmony_ci        l = X509_get_version(x);
76e1051a39Sopenharmony_ci        if (l >= X509_VERSION_1 && l <= X509_VERSION_3) {
77e1051a39Sopenharmony_ci            if (BIO_printf(bp, "%8sVersion: %ld (0x%lx)\n", "", l + 1, (unsigned long)l) <= 0)
78e1051a39Sopenharmony_ci                goto err;
79e1051a39Sopenharmony_ci        } else {
80e1051a39Sopenharmony_ci            if (BIO_printf(bp, "%8sVersion: Unknown (%ld)\n", "", l) <= 0)
81e1051a39Sopenharmony_ci                goto err;
82e1051a39Sopenharmony_ci        }
83e1051a39Sopenharmony_ci    }
84e1051a39Sopenharmony_ci    if (!(cflag & X509_FLAG_NO_SERIAL)) {
85e1051a39Sopenharmony_ci        const ASN1_INTEGER *bs = X509_get0_serialNumber(x);
86e1051a39Sopenharmony_ci
87e1051a39Sopenharmony_ci        if (BIO_write(bp, "        Serial Number:", 22) <= 0)
88e1051a39Sopenharmony_ci            goto err;
89e1051a39Sopenharmony_ci
90e1051a39Sopenharmony_ci        if (bs->length <= (int)sizeof(long)) {
91e1051a39Sopenharmony_ci                ERR_set_mark();
92e1051a39Sopenharmony_ci                l = ASN1_INTEGER_get(bs);
93e1051a39Sopenharmony_ci                ERR_pop_to_mark();
94e1051a39Sopenharmony_ci        } else {
95e1051a39Sopenharmony_ci            l = -1;
96e1051a39Sopenharmony_ci        }
97e1051a39Sopenharmony_ci        if (l != -1) {
98e1051a39Sopenharmony_ci            unsigned long ul;
99e1051a39Sopenharmony_ci            if (bs->type == V_ASN1_NEG_INTEGER) {
100e1051a39Sopenharmony_ci                ul = 0 - (unsigned long)l;
101e1051a39Sopenharmony_ci                neg = "-";
102e1051a39Sopenharmony_ci            } else {
103e1051a39Sopenharmony_ci                ul = l;
104e1051a39Sopenharmony_ci                neg = "";
105e1051a39Sopenharmony_ci            }
106e1051a39Sopenharmony_ci            if (BIO_printf(bp, " %s%lu (%s0x%lx)\n", neg, ul, neg, ul) <= 0)
107e1051a39Sopenharmony_ci                goto err;
108e1051a39Sopenharmony_ci        } else {
109e1051a39Sopenharmony_ci            neg = (bs->type == V_ASN1_NEG_INTEGER) ? " (Negative)" : "";
110e1051a39Sopenharmony_ci            if (BIO_printf(bp, "\n%12s%s", "", neg) <= 0)
111e1051a39Sopenharmony_ci                goto err;
112e1051a39Sopenharmony_ci
113e1051a39Sopenharmony_ci            for (i = 0; i < bs->length; i++) {
114e1051a39Sopenharmony_ci                if (BIO_printf(bp, "%02x%c", bs->data[i],
115e1051a39Sopenharmony_ci                               ((i + 1 == bs->length) ? '\n' : ':')) <= 0)
116e1051a39Sopenharmony_ci                    goto err;
117e1051a39Sopenharmony_ci            }
118e1051a39Sopenharmony_ci        }
119e1051a39Sopenharmony_ci
120e1051a39Sopenharmony_ci    }
121e1051a39Sopenharmony_ci
122e1051a39Sopenharmony_ci    if (!(cflag & X509_FLAG_NO_SIGNAME)) {
123e1051a39Sopenharmony_ci        const X509_ALGOR *tsig_alg = X509_get0_tbs_sigalg(x);
124e1051a39Sopenharmony_ci
125e1051a39Sopenharmony_ci        if (BIO_puts(bp, "    ") <= 0)
126e1051a39Sopenharmony_ci            goto err;
127e1051a39Sopenharmony_ci        if (X509_signature_print(bp, tsig_alg, NULL) <= 0)
128e1051a39Sopenharmony_ci            goto err;
129e1051a39Sopenharmony_ci    }
130e1051a39Sopenharmony_ci
131e1051a39Sopenharmony_ci    if (!(cflag & X509_FLAG_NO_ISSUER)) {
132e1051a39Sopenharmony_ci        if (BIO_printf(bp, "        Issuer:%c", mlch) <= 0)
133e1051a39Sopenharmony_ci            goto err;
134e1051a39Sopenharmony_ci        if (X509_NAME_print_ex(bp, X509_get_issuer_name(x), nmindent, nmflags)
135e1051a39Sopenharmony_ci            < printok)
136e1051a39Sopenharmony_ci            goto err;
137e1051a39Sopenharmony_ci        if (BIO_write(bp, "\n", 1) <= 0)
138e1051a39Sopenharmony_ci            goto err;
139e1051a39Sopenharmony_ci    }
140e1051a39Sopenharmony_ci    if (!(cflag & X509_FLAG_NO_VALIDITY)) {
141e1051a39Sopenharmony_ci        if (BIO_write(bp, "        Validity\n", 17) <= 0)
142e1051a39Sopenharmony_ci            goto err;
143e1051a39Sopenharmony_ci        if (BIO_write(bp, "            Not Before: ", 24) <= 0)
144e1051a39Sopenharmony_ci            goto err;
145e1051a39Sopenharmony_ci        if (ossl_asn1_time_print_ex(bp, X509_get0_notBefore(x), ASN1_DTFLGS_RFC822) == 0)
146e1051a39Sopenharmony_ci            goto err;
147e1051a39Sopenharmony_ci        if (BIO_write(bp, "\n            Not After : ", 25) <= 0)
148e1051a39Sopenharmony_ci            goto err;
149e1051a39Sopenharmony_ci        if (ossl_asn1_time_print_ex(bp, X509_get0_notAfter(x), ASN1_DTFLGS_RFC822) == 0)
150e1051a39Sopenharmony_ci            goto err;
151e1051a39Sopenharmony_ci        if (BIO_write(bp, "\n", 1) <= 0)
152e1051a39Sopenharmony_ci            goto err;
153e1051a39Sopenharmony_ci    }
154e1051a39Sopenharmony_ci    if (!(cflag & X509_FLAG_NO_SUBJECT)) {
155e1051a39Sopenharmony_ci        if (BIO_printf(bp, "        Subject:%c", mlch) <= 0)
156e1051a39Sopenharmony_ci            goto err;
157e1051a39Sopenharmony_ci        if (X509_NAME_print_ex
158e1051a39Sopenharmony_ci            (bp, X509_get_subject_name(x), nmindent, nmflags) < printok)
159e1051a39Sopenharmony_ci            goto err;
160e1051a39Sopenharmony_ci        if (BIO_write(bp, "\n", 1) <= 0)
161e1051a39Sopenharmony_ci            goto err;
162e1051a39Sopenharmony_ci    }
163e1051a39Sopenharmony_ci    if (!(cflag & X509_FLAG_NO_PUBKEY)) {
164e1051a39Sopenharmony_ci        X509_PUBKEY *xpkey = X509_get_X509_PUBKEY(x);
165e1051a39Sopenharmony_ci        ASN1_OBJECT *xpoid;
166e1051a39Sopenharmony_ci        X509_PUBKEY_get0_param(&xpoid, NULL, NULL, NULL, xpkey);
167e1051a39Sopenharmony_ci        if (BIO_write(bp, "        Subject Public Key Info:\n", 33) <= 0)
168e1051a39Sopenharmony_ci            goto err;
169e1051a39Sopenharmony_ci        if (BIO_printf(bp, "%12sPublic Key Algorithm: ", "") <= 0)
170e1051a39Sopenharmony_ci            goto err;
171e1051a39Sopenharmony_ci        if (i2a_ASN1_OBJECT(bp, xpoid) <= 0)
172e1051a39Sopenharmony_ci            goto err;
173e1051a39Sopenharmony_ci        if (BIO_puts(bp, "\n") <= 0)
174e1051a39Sopenharmony_ci            goto err;
175e1051a39Sopenharmony_ci
176e1051a39Sopenharmony_ci        pkey = X509_get0_pubkey(x);
177e1051a39Sopenharmony_ci        if (pkey == NULL) {
178e1051a39Sopenharmony_ci            BIO_printf(bp, "%12sUnable to load Public Key\n", "");
179e1051a39Sopenharmony_ci            ERR_print_errors(bp);
180e1051a39Sopenharmony_ci        } else {
181e1051a39Sopenharmony_ci            EVP_PKEY_print_public(bp, pkey, 16, NULL);
182e1051a39Sopenharmony_ci        }
183e1051a39Sopenharmony_ci    }
184e1051a39Sopenharmony_ci
185e1051a39Sopenharmony_ci    if (!(cflag & X509_FLAG_NO_IDS)) {
186e1051a39Sopenharmony_ci        const ASN1_BIT_STRING *iuid, *suid;
187e1051a39Sopenharmony_ci        X509_get0_uids(x, &iuid, &suid);
188e1051a39Sopenharmony_ci        if (iuid != NULL) {
189e1051a39Sopenharmony_ci            if (BIO_printf(bp, "%8sIssuer Unique ID: ", "") <= 0)
190e1051a39Sopenharmony_ci                goto err;
191e1051a39Sopenharmony_ci            if (!X509_signature_dump(bp, iuid, 12))
192e1051a39Sopenharmony_ci                goto err;
193e1051a39Sopenharmony_ci        }
194e1051a39Sopenharmony_ci        if (suid != NULL) {
195e1051a39Sopenharmony_ci            if (BIO_printf(bp, "%8sSubject Unique ID: ", "") <= 0)
196e1051a39Sopenharmony_ci                goto err;
197e1051a39Sopenharmony_ci            if (!X509_signature_dump(bp, suid, 12))
198e1051a39Sopenharmony_ci                goto err;
199e1051a39Sopenharmony_ci        }
200e1051a39Sopenharmony_ci    }
201e1051a39Sopenharmony_ci
202e1051a39Sopenharmony_ci    if (!(cflag & X509_FLAG_NO_EXTENSIONS)
203e1051a39Sopenharmony_ci        && !X509V3_extensions_print(bp, "X509v3 extensions",
204e1051a39Sopenharmony_ci                                    X509_get0_extensions(x), cflag, 8))
205e1051a39Sopenharmony_ci        goto err;
206e1051a39Sopenharmony_ci
207e1051a39Sopenharmony_ci    if (!(cflag & X509_FLAG_NO_SIGDUMP)) {
208e1051a39Sopenharmony_ci        const X509_ALGOR *sig_alg;
209e1051a39Sopenharmony_ci        const ASN1_BIT_STRING *sig;
210e1051a39Sopenharmony_ci        X509_get0_signature(&sig, &sig_alg, x);
211e1051a39Sopenharmony_ci        if (X509_signature_print(bp, sig_alg, sig) <= 0)
212e1051a39Sopenharmony_ci            goto err;
213e1051a39Sopenharmony_ci    }
214e1051a39Sopenharmony_ci    if (!(cflag & X509_FLAG_NO_AUX)) {
215e1051a39Sopenharmony_ci        if (!X509_aux_print(bp, x, 0))
216e1051a39Sopenharmony_ci            goto err;
217e1051a39Sopenharmony_ci    }
218e1051a39Sopenharmony_ci    ret = 1;
219e1051a39Sopenharmony_ci err:
220e1051a39Sopenharmony_ci    OPENSSL_free(m);
221e1051a39Sopenharmony_ci    return ret;
222e1051a39Sopenharmony_ci}
223e1051a39Sopenharmony_ci
224e1051a39Sopenharmony_ciint X509_ocspid_print(BIO *bp, X509 *x)
225e1051a39Sopenharmony_ci{
226e1051a39Sopenharmony_ci    unsigned char *der = NULL;
227e1051a39Sopenharmony_ci    unsigned char *dertmp;
228e1051a39Sopenharmony_ci    int derlen;
229e1051a39Sopenharmony_ci    int i;
230e1051a39Sopenharmony_ci    unsigned char SHA1md[SHA_DIGEST_LENGTH];
231e1051a39Sopenharmony_ci    ASN1_BIT_STRING *keybstr;
232e1051a39Sopenharmony_ci    const X509_NAME *subj;
233e1051a39Sopenharmony_ci    EVP_MD *md = NULL;
234e1051a39Sopenharmony_ci
235e1051a39Sopenharmony_ci    if (x == NULL || bp == NULL)
236e1051a39Sopenharmony_ci        return 0;
237e1051a39Sopenharmony_ci    /*
238e1051a39Sopenharmony_ci     * display the hash of the subject as it would appear in OCSP requests
239e1051a39Sopenharmony_ci     */
240e1051a39Sopenharmony_ci    if (BIO_printf(bp, "        Subject OCSP hash: ") <= 0)
241e1051a39Sopenharmony_ci        goto err;
242e1051a39Sopenharmony_ci    subj = X509_get_subject_name(x);
243e1051a39Sopenharmony_ci    derlen = i2d_X509_NAME(subj, NULL);
244e1051a39Sopenharmony_ci    if (derlen <= 0)
245e1051a39Sopenharmony_ci        goto err;
246e1051a39Sopenharmony_ci    if ((der = dertmp = OPENSSL_malloc(derlen)) == NULL)
247e1051a39Sopenharmony_ci        goto err;
248e1051a39Sopenharmony_ci    i2d_X509_NAME(subj, &dertmp);
249e1051a39Sopenharmony_ci
250e1051a39Sopenharmony_ci    md = EVP_MD_fetch(x->libctx, SN_sha1, x->propq);
251e1051a39Sopenharmony_ci    if (md == NULL)
252e1051a39Sopenharmony_ci        goto err;
253e1051a39Sopenharmony_ci    if (!EVP_Digest(der, derlen, SHA1md, NULL, md, NULL))
254e1051a39Sopenharmony_ci        goto err;
255e1051a39Sopenharmony_ci    for (i = 0; i < SHA_DIGEST_LENGTH; i++) {
256e1051a39Sopenharmony_ci        if (BIO_printf(bp, "%02X", SHA1md[i]) <= 0)
257e1051a39Sopenharmony_ci            goto err;
258e1051a39Sopenharmony_ci    }
259e1051a39Sopenharmony_ci    OPENSSL_free(der);
260e1051a39Sopenharmony_ci    der = NULL;
261e1051a39Sopenharmony_ci
262e1051a39Sopenharmony_ci    /*
263e1051a39Sopenharmony_ci     * display the hash of the public key as it would appear in OCSP requests
264e1051a39Sopenharmony_ci     */
265e1051a39Sopenharmony_ci    if (BIO_printf(bp, "\n        Public key OCSP hash: ") <= 0)
266e1051a39Sopenharmony_ci        goto err;
267e1051a39Sopenharmony_ci
268e1051a39Sopenharmony_ci    keybstr = X509_get0_pubkey_bitstr(x);
269e1051a39Sopenharmony_ci
270e1051a39Sopenharmony_ci    if (keybstr == NULL)
271e1051a39Sopenharmony_ci        goto err;
272e1051a39Sopenharmony_ci
273e1051a39Sopenharmony_ci    if (!EVP_Digest(ASN1_STRING_get0_data(keybstr),
274e1051a39Sopenharmony_ci                    ASN1_STRING_length(keybstr), SHA1md, NULL, md, NULL))
275e1051a39Sopenharmony_ci        goto err;
276e1051a39Sopenharmony_ci    for (i = 0; i < SHA_DIGEST_LENGTH; i++) {
277e1051a39Sopenharmony_ci        if (BIO_printf(bp, "%02X", SHA1md[i]) <= 0)
278e1051a39Sopenharmony_ci            goto err;
279e1051a39Sopenharmony_ci    }
280e1051a39Sopenharmony_ci    BIO_printf(bp, "\n");
281e1051a39Sopenharmony_ci    EVP_MD_free(md);
282e1051a39Sopenharmony_ci
283e1051a39Sopenharmony_ci    return 1;
284e1051a39Sopenharmony_ci err:
285e1051a39Sopenharmony_ci    OPENSSL_free(der);
286e1051a39Sopenharmony_ci    EVP_MD_free(md);
287e1051a39Sopenharmony_ci    return 0;
288e1051a39Sopenharmony_ci}
289e1051a39Sopenharmony_ci
290e1051a39Sopenharmony_ciint X509_signature_dump(BIO *bp, const ASN1_STRING *sig, int indent)
291e1051a39Sopenharmony_ci{
292e1051a39Sopenharmony_ci    const unsigned char *s;
293e1051a39Sopenharmony_ci    int i, n;
294e1051a39Sopenharmony_ci
295e1051a39Sopenharmony_ci    n = sig->length;
296e1051a39Sopenharmony_ci    s = sig->data;
297e1051a39Sopenharmony_ci    for (i = 0; i < n; i++) {
298e1051a39Sopenharmony_ci        if ((i % 18) == 0) {
299e1051a39Sopenharmony_ci            if (i > 0 && BIO_write(bp, "\n", 1) <= 0)
300e1051a39Sopenharmony_ci                return 0;
301e1051a39Sopenharmony_ci            if (BIO_indent(bp, indent, indent) <= 0)
302e1051a39Sopenharmony_ci                return 0;
303e1051a39Sopenharmony_ci        }
304e1051a39Sopenharmony_ci        if (BIO_printf(bp, "%02x%s", s[i], ((i + 1) == n) ? "" : ":") <= 0)
305e1051a39Sopenharmony_ci            return 0;
306e1051a39Sopenharmony_ci    }
307e1051a39Sopenharmony_ci    if (BIO_write(bp, "\n", 1) != 1)
308e1051a39Sopenharmony_ci        return 0;
309e1051a39Sopenharmony_ci
310e1051a39Sopenharmony_ci    return 1;
311e1051a39Sopenharmony_ci}
312e1051a39Sopenharmony_ci
313e1051a39Sopenharmony_ciint X509_signature_print(BIO *bp, const X509_ALGOR *sigalg,
314e1051a39Sopenharmony_ci                         const ASN1_STRING *sig)
315e1051a39Sopenharmony_ci{
316e1051a39Sopenharmony_ci    int sig_nid;
317e1051a39Sopenharmony_ci    int indent = 4;
318e1051a39Sopenharmony_ci    if (BIO_printf(bp, "%*sSignature Algorithm: ", indent, "") <= 0)
319e1051a39Sopenharmony_ci        return 0;
320e1051a39Sopenharmony_ci    if (i2a_ASN1_OBJECT(bp, sigalg->algorithm) <= 0)
321e1051a39Sopenharmony_ci        return 0;
322e1051a39Sopenharmony_ci
323e1051a39Sopenharmony_ci    if (sig && BIO_printf(bp, "\n%*sSignature Value:", indent, "") <= 0)
324e1051a39Sopenharmony_ci        return 0;
325e1051a39Sopenharmony_ci    sig_nid = OBJ_obj2nid(sigalg->algorithm);
326e1051a39Sopenharmony_ci    if (sig_nid != NID_undef) {
327e1051a39Sopenharmony_ci        int pkey_nid, dig_nid;
328e1051a39Sopenharmony_ci        const EVP_PKEY_ASN1_METHOD *ameth;
329e1051a39Sopenharmony_ci        if (OBJ_find_sigid_algs(sig_nid, &dig_nid, &pkey_nid)) {
330e1051a39Sopenharmony_ci            ameth = EVP_PKEY_asn1_find(NULL, pkey_nid);
331e1051a39Sopenharmony_ci            if (ameth && ameth->sig_print)
332e1051a39Sopenharmony_ci                return ameth->sig_print(bp, sigalg, sig, indent + 4, 0);
333e1051a39Sopenharmony_ci        }
334e1051a39Sopenharmony_ci    }
335e1051a39Sopenharmony_ci    if (BIO_write(bp, "\n", 1) != 1)
336e1051a39Sopenharmony_ci        return 0;
337e1051a39Sopenharmony_ci    if (sig)
338e1051a39Sopenharmony_ci        return X509_signature_dump(bp, sig, indent + 4);
339e1051a39Sopenharmony_ci    return 1;
340e1051a39Sopenharmony_ci}
341e1051a39Sopenharmony_ci
342e1051a39Sopenharmony_ciint X509_aux_print(BIO *out, X509 *x, int indent)
343e1051a39Sopenharmony_ci{
344e1051a39Sopenharmony_ci    char oidstr[80], first;
345e1051a39Sopenharmony_ci    STACK_OF(ASN1_OBJECT) *trust, *reject;
346e1051a39Sopenharmony_ci    const unsigned char *alias, *keyid;
347e1051a39Sopenharmony_ci    int keyidlen;
348e1051a39Sopenharmony_ci    int i;
349e1051a39Sopenharmony_ci    if (X509_trusted(x) == 0)
350e1051a39Sopenharmony_ci        return 1;
351e1051a39Sopenharmony_ci    trust = X509_get0_trust_objects(x);
352e1051a39Sopenharmony_ci    reject = X509_get0_reject_objects(x);
353e1051a39Sopenharmony_ci    if (trust) {
354e1051a39Sopenharmony_ci        first = 1;
355e1051a39Sopenharmony_ci        BIO_printf(out, "%*sTrusted Uses:\n%*s", indent, "", indent + 2, "");
356e1051a39Sopenharmony_ci        for (i = 0; i < sk_ASN1_OBJECT_num(trust); i++) {
357e1051a39Sopenharmony_ci            if (!first)
358e1051a39Sopenharmony_ci                BIO_puts(out, ", ");
359e1051a39Sopenharmony_ci            else
360e1051a39Sopenharmony_ci                first = 0;
361e1051a39Sopenharmony_ci            OBJ_obj2txt(oidstr, sizeof(oidstr),
362e1051a39Sopenharmony_ci                        sk_ASN1_OBJECT_value(trust, i), 0);
363e1051a39Sopenharmony_ci            BIO_puts(out, oidstr);
364e1051a39Sopenharmony_ci        }
365e1051a39Sopenharmony_ci        BIO_puts(out, "\n");
366e1051a39Sopenharmony_ci    } else
367e1051a39Sopenharmony_ci        BIO_printf(out, "%*sNo Trusted Uses.\n", indent, "");
368e1051a39Sopenharmony_ci    if (reject) {
369e1051a39Sopenharmony_ci        first = 1;
370e1051a39Sopenharmony_ci        BIO_printf(out, "%*sRejected Uses:\n%*s", indent, "", indent + 2, "");
371e1051a39Sopenharmony_ci        for (i = 0; i < sk_ASN1_OBJECT_num(reject); i++) {
372e1051a39Sopenharmony_ci            if (!first)
373e1051a39Sopenharmony_ci                BIO_puts(out, ", ");
374e1051a39Sopenharmony_ci            else
375e1051a39Sopenharmony_ci                first = 0;
376e1051a39Sopenharmony_ci            OBJ_obj2txt(oidstr, sizeof(oidstr),
377e1051a39Sopenharmony_ci                        sk_ASN1_OBJECT_value(reject, i), 0);
378e1051a39Sopenharmony_ci            BIO_puts(out, oidstr);
379e1051a39Sopenharmony_ci        }
380e1051a39Sopenharmony_ci        BIO_puts(out, "\n");
381e1051a39Sopenharmony_ci    } else
382e1051a39Sopenharmony_ci        BIO_printf(out, "%*sNo Rejected Uses.\n", indent, "");
383e1051a39Sopenharmony_ci    alias = X509_alias_get0(x, &i);
384e1051a39Sopenharmony_ci    if (alias)
385e1051a39Sopenharmony_ci        BIO_printf(out, "%*sAlias: %.*s\n", indent, "", i, alias);
386e1051a39Sopenharmony_ci    keyid = X509_keyid_get0(x, &keyidlen);
387e1051a39Sopenharmony_ci    if (keyid) {
388e1051a39Sopenharmony_ci        BIO_printf(out, "%*sKey Id: ", indent, "");
389e1051a39Sopenharmony_ci        for (i = 0; i < keyidlen; i++)
390e1051a39Sopenharmony_ci            BIO_printf(out, "%s%02X", i ? ":" : "", keyid[i]);
391e1051a39Sopenharmony_ci        BIO_write(out, "\n", 1);
392e1051a39Sopenharmony_ci    }
393e1051a39Sopenharmony_ci    return 1;
394e1051a39Sopenharmony_ci}
395e1051a39Sopenharmony_ci
396e1051a39Sopenharmony_ci/*
397e1051a39Sopenharmony_ci * Helper functions for improving certificate verification error diagnostics
398e1051a39Sopenharmony_ci */
399e1051a39Sopenharmony_ci
400e1051a39Sopenharmony_ciint ossl_x509_print_ex_brief(BIO *bio, X509 *cert, unsigned long neg_cflags)
401e1051a39Sopenharmony_ci{
402e1051a39Sopenharmony_ci    unsigned long flags = ASN1_STRFLGS_RFC2253 | ASN1_STRFLGS_ESC_QUOTE |
403e1051a39Sopenharmony_ci        XN_FLAG_SEP_CPLUS_SPC | XN_FLAG_FN_SN;
404e1051a39Sopenharmony_ci
405e1051a39Sopenharmony_ci    if (cert == NULL)
406e1051a39Sopenharmony_ci        return BIO_printf(bio, "    (no certificate)\n") > 0;
407e1051a39Sopenharmony_ci    if (BIO_printf(bio, "    certificate\n") <= 0
408e1051a39Sopenharmony_ci            || !X509_print_ex(bio, cert, flags, ~X509_FLAG_NO_SUBJECT))
409e1051a39Sopenharmony_ci        return 0;
410e1051a39Sopenharmony_ci    if (X509_check_issued((X509 *)cert, cert) == X509_V_OK) {
411e1051a39Sopenharmony_ci        if (BIO_printf(bio, "        self-issued\n") <= 0)
412e1051a39Sopenharmony_ci            return 0;
413e1051a39Sopenharmony_ci    } else {
414e1051a39Sopenharmony_ci        if (BIO_printf(bio, " ") <= 0
415e1051a39Sopenharmony_ci            || !X509_print_ex(bio, cert, flags, ~X509_FLAG_NO_ISSUER))
416e1051a39Sopenharmony_ci            return 0;
417e1051a39Sopenharmony_ci    }
418e1051a39Sopenharmony_ci    if (!X509_print_ex(bio, cert, flags,
419e1051a39Sopenharmony_ci                       ~(X509_FLAG_NO_SERIAL | X509_FLAG_NO_VALIDITY)))
420e1051a39Sopenharmony_ci        return 0;
421e1051a39Sopenharmony_ci    if (X509_cmp_current_time(X509_get0_notBefore(cert)) > 0)
422e1051a39Sopenharmony_ci        if (BIO_printf(bio, "        not yet valid\n") <= 0)
423e1051a39Sopenharmony_ci            return 0;
424e1051a39Sopenharmony_ci    if (X509_cmp_current_time(X509_get0_notAfter(cert)) < 0)
425e1051a39Sopenharmony_ci        if (BIO_printf(bio, "        no more valid\n") <= 0)
426e1051a39Sopenharmony_ci            return 0;
427e1051a39Sopenharmony_ci    return X509_print_ex(bio, cert, flags,
428e1051a39Sopenharmony_ci                         ~neg_cflags & ~X509_FLAG_EXTENSIONS_ONLY_KID);
429e1051a39Sopenharmony_ci}
430e1051a39Sopenharmony_ci
431e1051a39Sopenharmony_cistatic int print_certs(BIO *bio, const STACK_OF(X509) *certs)
432e1051a39Sopenharmony_ci{
433e1051a39Sopenharmony_ci    int i;
434e1051a39Sopenharmony_ci
435e1051a39Sopenharmony_ci    if (certs == NULL || sk_X509_num(certs) <= 0)
436e1051a39Sopenharmony_ci        return BIO_printf(bio, "    (no certificates)\n") >= 0;
437e1051a39Sopenharmony_ci
438e1051a39Sopenharmony_ci    for (i = 0; i < sk_X509_num(certs); i++) {
439e1051a39Sopenharmony_ci        X509 *cert = sk_X509_value(certs, i);
440e1051a39Sopenharmony_ci
441e1051a39Sopenharmony_ci        if (cert != NULL) {
442e1051a39Sopenharmony_ci            if (!ossl_x509_print_ex_brief(bio, cert, 0))
443e1051a39Sopenharmony_ci                return 0;
444e1051a39Sopenharmony_ci            if (!X509V3_extensions_print(bio, NULL,
445e1051a39Sopenharmony_ci                                         X509_get0_extensions(cert),
446e1051a39Sopenharmony_ci                                         X509_FLAG_EXTENSIONS_ONLY_KID, 8))
447e1051a39Sopenharmony_ci                return 0;
448e1051a39Sopenharmony_ci            }
449e1051a39Sopenharmony_ci    }
450e1051a39Sopenharmony_ci    return 1;
451e1051a39Sopenharmony_ci}
452e1051a39Sopenharmony_ci
453e1051a39Sopenharmony_cistatic int print_store_certs(BIO *bio, X509_STORE *store)
454e1051a39Sopenharmony_ci{
455e1051a39Sopenharmony_ci    if (store != NULL) {
456e1051a39Sopenharmony_ci        STACK_OF(X509) *certs = X509_STORE_get1_all_certs(store);
457e1051a39Sopenharmony_ci        int ret = print_certs(bio, certs);
458e1051a39Sopenharmony_ci
459e1051a39Sopenharmony_ci        sk_X509_pop_free(certs, X509_free);
460e1051a39Sopenharmony_ci        return ret;
461e1051a39Sopenharmony_ci    } else {
462e1051a39Sopenharmony_ci        return BIO_printf(bio, "    (no trusted store)\n") >= 0;
463e1051a39Sopenharmony_ci    }
464e1051a39Sopenharmony_ci}
465e1051a39Sopenharmony_ci
466e1051a39Sopenharmony_ci/* Extend the error queue with details on a failed cert verification */
467e1051a39Sopenharmony_ciint X509_STORE_CTX_print_verify_cb(int ok, X509_STORE_CTX *ctx)
468e1051a39Sopenharmony_ci{
469e1051a39Sopenharmony_ci    if (ok == 0 && ctx != NULL) {
470e1051a39Sopenharmony_ci        int cert_error = X509_STORE_CTX_get_error(ctx);
471e1051a39Sopenharmony_ci        BIO *bio = BIO_new(BIO_s_mem()); /* may be NULL */
472e1051a39Sopenharmony_ci
473e1051a39Sopenharmony_ci        BIO_printf(bio, "%s at depth = %d error = %d (%s)\n",
474e1051a39Sopenharmony_ci                   X509_STORE_CTX_get0_parent_ctx(ctx) != NULL
475e1051a39Sopenharmony_ci                   ? "CRL path validation"
476e1051a39Sopenharmony_ci                   : "Certificate verification",
477e1051a39Sopenharmony_ci                   X509_STORE_CTX_get_error_depth(ctx),
478e1051a39Sopenharmony_ci                   cert_error, X509_verify_cert_error_string(cert_error));
479e1051a39Sopenharmony_ci        {
480e1051a39Sopenharmony_ci            X509_STORE *ts = X509_STORE_CTX_get0_store(ctx);
481e1051a39Sopenharmony_ci            X509_VERIFY_PARAM *vpm = X509_STORE_get0_param(ts);
482e1051a39Sopenharmony_ci            char *str;
483e1051a39Sopenharmony_ci            int idx = 0;
484e1051a39Sopenharmony_ci
485e1051a39Sopenharmony_ci            switch (cert_error) {
486e1051a39Sopenharmony_ci            case X509_V_ERR_HOSTNAME_MISMATCH:
487e1051a39Sopenharmony_ci                BIO_printf(bio, "Expected hostname(s) = ");
488e1051a39Sopenharmony_ci                while ((str = X509_VERIFY_PARAM_get0_host(vpm, idx++)) != NULL)
489e1051a39Sopenharmony_ci                    BIO_printf(bio, "%s%s", idx == 1 ? "" : ", ", str);
490e1051a39Sopenharmony_ci                BIO_printf(bio, "\n");
491e1051a39Sopenharmony_ci                break;
492e1051a39Sopenharmony_ci            case X509_V_ERR_EMAIL_MISMATCH:
493e1051a39Sopenharmony_ci                str = X509_VERIFY_PARAM_get0_email(vpm);
494e1051a39Sopenharmony_ci                if (str != NULL)
495e1051a39Sopenharmony_ci                    BIO_printf(bio, "Expected email address = %s\n", str);
496e1051a39Sopenharmony_ci                break;
497e1051a39Sopenharmony_ci            case X509_V_ERR_IP_ADDRESS_MISMATCH:
498e1051a39Sopenharmony_ci                str = X509_VERIFY_PARAM_get1_ip_asc(vpm);
499e1051a39Sopenharmony_ci                if (str != NULL)
500e1051a39Sopenharmony_ci                    BIO_printf(bio, "Expected IP address = %s\n", str);
501e1051a39Sopenharmony_ci                OPENSSL_free(str);
502e1051a39Sopenharmony_ci                break;
503e1051a39Sopenharmony_ci            default:
504e1051a39Sopenharmony_ci                break;
505e1051a39Sopenharmony_ci            }
506e1051a39Sopenharmony_ci        }
507e1051a39Sopenharmony_ci
508e1051a39Sopenharmony_ci        BIO_printf(bio, "Failure for:\n");
509e1051a39Sopenharmony_ci        ossl_x509_print_ex_brief(bio, X509_STORE_CTX_get_current_cert(ctx),
510e1051a39Sopenharmony_ci                                 X509_FLAG_NO_EXTENSIONS);
511e1051a39Sopenharmony_ci        if (cert_error == X509_V_ERR_CERT_UNTRUSTED
512e1051a39Sopenharmony_ci                || cert_error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT
513e1051a39Sopenharmony_ci                || cert_error == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN
514e1051a39Sopenharmony_ci                || cert_error == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT
515e1051a39Sopenharmony_ci                || cert_error == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY
516e1051a39Sopenharmony_ci                || cert_error == X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER
517e1051a39Sopenharmony_ci                || cert_error == X509_V_ERR_STORE_LOOKUP) {
518e1051a39Sopenharmony_ci            BIO_printf(bio, "Non-trusted certs:\n");
519e1051a39Sopenharmony_ci            print_certs(bio, X509_STORE_CTX_get0_untrusted(ctx));
520e1051a39Sopenharmony_ci            BIO_printf(bio, "Certs in trust store:\n");
521e1051a39Sopenharmony_ci            print_store_certs(bio, X509_STORE_CTX_get0_store(ctx));
522e1051a39Sopenharmony_ci        }
523e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_X509, X509_R_CERTIFICATE_VERIFICATION_FAILED);
524e1051a39Sopenharmony_ci        ERR_add_error_mem_bio("\n", bio);
525e1051a39Sopenharmony_ci        BIO_free(bio);
526e1051a39Sopenharmony_ci    }
527e1051a39Sopenharmony_ci
528e1051a39Sopenharmony_ci    return ok;
529e1051a39Sopenharmony_ci}
530