aboutsummaryrefslogtreecommitdiff
path: root/openssl/demos/tunala/cb.c
blob: 684a07f0862d2755921c171e98b59c7a1d85f1d8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#include "tunala.h"

#ifndef NO_OPENSSL

/* For callbacks generating output, here are their file-descriptors. */
static FILE *fp_cb_ssl_info = NULL;
static FILE *fp_cb_ssl_verify = NULL;
/*-
 * Output level:
 *     0 = nothing,
 *     1 = minimal, just errors,
 *     2 = minimal, all steps,
 *     3 = detail, all steps */
static unsigned int cb_ssl_verify_level = 1;

/* Other static rubbish (to mirror s_cb.c where required) */
static int int_verify_depth = 10;

/*
 * This function is largely borrowed from the one used in OpenSSL's
 * "s_client" and "s_server" utilities.
 */
void cb_ssl_info(const SSL *s, int where, int ret)
{
    const char *str1, *str2;
    int w;

    if (!fp_cb_ssl_info)
        return;

    w = where & ~SSL_ST_MASK;
    str1 = (w & SSL_ST_CONNECT ? "SSL_connect" : (w & SSL_ST_ACCEPT ?
                                                  "SSL_accept" :
                                                  "undefined")), str2 =
        SSL_state_string_long(s);

    if (where & SSL_CB_LOOP)
        fprintf(fp_cb_ssl_info, "(%s) %s\n", str1, str2);
    else if (where & SSL_CB_EXIT) {
        if (ret == 0)
            fprintf(fp_cb_ssl_info, "(%s) failed in %s\n", str1, str2);
        /*
         * In a non-blocking model, we get a few of these "error"s simply
         * because we're calling "reads" and "writes" on the state-machine
         * that are virtual NOPs simply to avoid wasting the time seeing if
         * we *should* call them. Removing this case makes the "-out_state"
         * output a lot easier on the eye.
         */
# if 0
        else if (ret < 0)
            fprintf(fp_cb_ssl_info, "%s:error in %s\n", str1, str2);
# endif
    }
}

void cb_ssl_info_set_output(FILE *fp)
{
    fp_cb_ssl_info = fp;
}

static const char *int_reason_no_issuer =
    "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT";
static const char *int_reason_not_yet = "X509_V_ERR_CERT_NOT_YET_VALID";
static const char *int_reason_before =
    "X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD";
static const char *int_reason_expired = "X509_V_ERR_CERT_HAS_EXPIRED";
static const char *int_reason_after =
    "X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD";

/* Stolen wholesale from apps/s_cb.c :-) And since then, mutilated ... */
int cb_ssl_verify(int ok, X509_STORE_CTX *ctx)
{
    char buf1[256];             /* Used for the subject name */
    char buf2[256];             /* Used for the issuer name */
    const char *reason = NULL;  /* Error reason (if any) */
    X509 *err_cert;
    int err, depth;

    if (!fp_cb_ssl_verify || (cb_ssl_verify_level == 0))
        return ok;
    err_cert = X509_STORE_CTX_get_current_cert(ctx);
    err = X509_STORE_CTX_get_error(ctx);
    depth = X509_STORE_CTX_get_error_depth(ctx);

    buf1[0] = buf2[0] = '\0';
    /* Fill buf1 */
    X509_NAME_oneline(X509_get_subject_name(err_cert), buf1, 256);
    /* Fill buf2 */
    X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf2, 256);
    switch (ctx->error) {
    case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
        reason = int_reason_no_issuer;
        break;
    case X509_V_ERR_CERT_NOT_YET_VALID:
        reason = int_reason_not_yet;
        break;
    case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
        reason = int_reason_before;
        break;
    case X509_V_ERR_CERT_HAS_EXPIRED:
        reason = int_reason_expired;
        break;
    case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
        reason = int_reason_after;
        break;
    }

    if ((cb_ssl_verify_level == 1) && ok)
        return ok;
    fprintf(fp_cb_ssl_verify, "chain-depth=%d, ", depth);
    if (reason)
        fprintf(fp_cb_ssl_verify, "error=%s\n", reason);
    else
        fprintf(fp_cb_ssl_verify, "error=%d\n", err);
    if (cb_ssl_verify_level < 3)
        return ok;
    fprintf(fp_cb_ssl_verify, "--> subject = %s\n", buf1);
    fprintf(fp_cb_ssl_verify, "--> issuer  = %s\n", buf2);
    if (!ok)
        fprintf(fp_cb_ssl_verify, "--> verify error:num=%d:%s\n", err,
                X509_verify_cert_error_string(err));
    fprintf(fp_cb_ssl_verify, "--> verify return:%d\n", ok);
    return ok;
}

void cb_ssl_verify_set_output(FILE *fp)
{
    fp_cb_ssl_verify = fp;
}

void cb_ssl_verify_set_depth(unsigned int verify_depth)
{
    int_verify_depth = verify_depth;
}

void cb_ssl_verify_set_level(unsigned int level)
{
    if (level < 4)
        cb_ssl_verify_level = level;
}

RSA *cb_generate_tmp_rsa(SSL *s, int is_export, int keylength)
{
    /*
     * TODO: Perhaps make it so our global key can be generated on-the-fly
     * after certain intervals?
     */
    static RSA *rsa_tmp = NULL;
    BIGNUM *bn = NULL;
    int ok = 1;
    if (!rsa_tmp) {
        ok = 0;
        if (!(bn = BN_new()))
            goto end;
        if (!BN_set_word(bn, RSA_F4))
            goto end;
        if (!(rsa_tmp = RSA_new()))
            goto end;
        if (!RSA_generate_key_ex(rsa_tmp, keylength, bn, NULL))
            goto end;
        ok = 1;
    }
 end:
    if (bn)
        BN_free(bn);
    if (!ok) {
        RSA_free(rsa_tmp);
        rsa_tmp = NULL;
    }
    return rsa_tmp;
}

#endif                          /* !defined(NO_OPENSSL) */