Coverage Report

Created: 2023-09-25 06:06

/src/net-snmp/snmplib/snmp_openssl.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * snmp_openssl.c
3
 *
4
 * Portions of this file are subject to the following copyright(s).  See
5
 * the Net-SNMP's COPYING file for more details and other copyrights
6
 * that may apply:
7
 *
8
 * Portions of this file are copyrighted by:
9
 * Copyright (c) 2016 VMware, Inc. All rights reserved.
10
 * Use is subject to license terms specified in the COPYING file
11
 * distributed with the Net-SNMP package.
12
 */
13
14
#include <net-snmp/net-snmp-config.h>
15
16
#include <net-snmp/net-snmp-includes.h>
17
18
#include <net-snmp/net-snmp-features.h>
19
20
/** OpenSSL compat functions for apps */
21
#if defined(NETSNMP_USE_OPENSSL)
22
23
#include <string.h>
24
#include <net-snmp/library/openssl_config.h>
25
#include <openssl/dh.h>
26
27
#ifndef HAVE_DH_GET0_PQG
28
void
29
DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
30
{
31
   if (p != NULL)
32
       *p = dh->p;
33
   if (q != NULL)
34
       *q = dh->q;
35
   if (g != NULL)
36
       *g = dh->g;
37
}
38
#endif
39
40
#ifndef HAVE_DH_GET0_KEY
41
void
42
DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key)
43
{
44
   if (pub_key != NULL)
45
       *pub_key = dh->pub_key;
46
   if (priv_key != NULL)
47
       *priv_key = dh->priv_key;
48
}
49
#endif
50
51
#ifndef HAVE_DH_SET0_PQG
52
int
53
DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
54
{
55
   /* If the fields p and g in d are NULL, the corresponding input
56
    * parameters MUST be non-NULL.  q may remain NULL.
57
    */
58
   if ((dh->p == NULL && p == NULL)
59
       || (dh->g == NULL && g == NULL))
60
       return 0;
61
62
   if (p != NULL) {
63
       BN_free(dh->p);
64
       dh->p = p;
65
   }
66
   if (q != NULL) {
67
       BN_free(dh->q);
68
       dh->q = q;
69
   }
70
   if (g != NULL) {
71
       BN_free(dh->g);
72
       dh->g = g;
73
   }
74
75
   if (q != NULL) {
76
       dh->length = BN_num_bits(q);
77
   }
78
79
   return 1;
80
}
81
#endif
82
#endif /* defined(NETSNMP_USE_OPENSSL) */
83
84
/** TLS/DTLS certificatte support */
85
#if defined(NETSNMP_USE_OPENSSL) && defined(HAVE_LIBSSL) && !defined(NETSNMP_FEATURE_REMOVE_CERT_UTIL)
86
87
netsnmp_feature_require(container_free_all);
88
89
netsnmp_feature_child_of(openssl_cert_get_subjectAltNames, netsnmp_unused);
90
netsnmp_feature_child_of(openssl_ht2nid, netsnmp_unused);
91
netsnmp_feature_child_of(openssl_err_log, netsnmp_unused);
92
netsnmp_feature_child_of(cert_dump_names, netsnmp_unused);
93
94
#include <ctype.h>
95
96
#include <openssl/evp.h>
97
#include <openssl/ssl.h>
98
#include <openssl/x509.h>
99
#include <openssl/x509v3.h>
100
#include <openssl/err.h>
101
#include <openssl/objects.h>
102
103
#include <net-snmp/library/snmp_debug.h>
104
#include <net-snmp/library/cert_util.h>
105
#include <net-snmp/library/snmp_openssl.h>
106
107
static u_char have_started_already = 0;
108
109
/*
110
 * This code merely does openssl initialization so that multilpe
111
 * modules are safe to call netsnmp_init_openssl() for bootstrapping
112
 * without worrying about other callers that may have already done so.
113
 */
114
0
void netsnmp_init_openssl(void) {
115
116
    /* avoid duplicate calls */
117
0
    if (have_started_already)
118
0
        return;
119
0
    have_started_already = 1;
120
121
0
    DEBUGMSGTL(("snmp_openssl", "initializing\n"));
122
123
    /* Initializing OpenSSL */
124
0
#ifdef HAVE_SSL_LIBRARY_INIT
125
0
    SSL_library_init();
126
0
#endif
127
0
#ifdef HAVE_SSL_LOAD_ERROR_STRINGS
128
0
    SSL_load_error_strings();
129
0
#endif
130
#ifdef HAVE_ERR_LOAD_BIO_STRINGS
131
    ERR_load_BIO_strings();
132
#endif
133
0
#ifdef HAVE_OPENSSL_ADD_ALL_ALGORITHMS
134
0
    OpenSSL_add_all_algorithms();
135
0
#endif
136
0
}
137
138
/** netsnmp_openssl_cert_get_name: get subject name field from cert
139
 * @internal
140
 */
141
/** instead of exposing this function, make helper functions for each
142
 * field, like netsnmp_openssl_cert_get_commonName, below */
143
static char *
144
_cert_get_name(X509 *ocert, int which, char **buf, int *len, int flags)
145
0
{
146
0
    X509_NAME       *osubj_name;
147
0
    int              space;
148
0
    char            *buf_ptr;
149
150
0
    if ((NULL == ocert) || ((buf && !len) || (len && !buf)))
151
0
        return NULL;
152
153
0
    osubj_name = X509_get_subject_name(ocert);
154
0
    if (NULL == osubj_name) {
155
0
        DEBUGMSGT(("openssl:cert:name", "no subject name!\n"));
156
0
        return NULL;
157
0
    }
158
159
    /** see if buf is big enough, or allocate buf if none specified */
160
0
    space = X509_NAME_get_text_by_NID(osubj_name, which, NULL, 0);
161
0
    if (-1 == space)
162
0
        return NULL;
163
0
    ++space; /* for NUL */
164
0
    if (buf && *buf) {
165
0
        if (*len < space)
166
0
            return NULL;
167
0
        buf_ptr = *buf;
168
0
    }
169
0
    else {
170
0
        buf_ptr = calloc(1,space);
171
0
        if (!buf_ptr)
172
0
            return NULL;
173
0
    }
174
0
    space = X509_NAME_get_text_by_NID(osubj_name, which, buf_ptr, space);
175
0
    if (len)
176
0
        *len = space;
177
178
0
    return buf_ptr;
179
0
}
180
181
/** netsnmp_openssl_cert_get_subjectName: get subject name field from cert
182
 */
183
char *
184
netsnmp_openssl_cert_get_subjectName(X509 *ocert, char **buf, int *len)
185
0
{
186
0
    X509_NAME       *osubj_name;
187
0
    int              space;
188
0
    char            *buf_ptr;
189
190
0
    if ((NULL == ocert) || ((buf && !len) || (len && !buf)))
191
0
        return NULL;
192
193
0
    osubj_name = X509_get_subject_name(ocert);
194
0
    if (NULL == osubj_name) {
195
0
        DEBUGMSGT(("openssl:cert:name", "no subject name!\n"));
196
0
        return NULL;
197
0
    }
198
199
0
    if (buf) {
200
0
        buf_ptr = *buf;
201
0
        space = *len;
202
0
    }
203
0
    else {
204
0
        buf_ptr = NULL;
205
0
        space = 0;
206
0
    }
207
0
    buf_ptr = X509_NAME_oneline(osubj_name, buf_ptr, space);
208
0
    if (len)
209
0
        *len = strlen(buf_ptr);
210
211
0
    return buf_ptr;
212
0
}
213
214
/** netsnmp_openssl_cert_get_commonName: get commonName for cert.
215
 * if a pointer to a buffer and its length are specified, they will be
216
 * used. otherwise, a new buffer will be allocated, which the caller will
217
 * be responsbile for releasing.
218
 */
219
char *
220
netsnmp_openssl_cert_get_commonName(X509 *ocert, char **buf, int *len)
221
0
{
222
0
    return _cert_get_name(ocert, NID_commonName, buf, len, 0);
223
0
}
224
225
#ifndef NETSNMP_FEATURE_REMOVE_CERT_DUMP_NAMES
226
227
/** netsnmp_openssl_cert_dump_name: dump subject names in cert
228
 */
229
void
230
netsnmp_openssl_cert_dump_names(X509 *ocert)
231
0
{
232
0
    int              i, onid;
233
0
    X509_NAME_ENTRY *oname_entry;
234
0
    ASN1_STRING     *oname_value;
235
0
    X509_NAME       *osubj_name;
236
0
    const char      *prefix_short, *prefix_long;
237
238
0
    if (NULL == ocert)
239
0
        return;
240
241
0
    osubj_name = X509_get_subject_name(ocert);
242
0
    if (NULL == osubj_name) {
243
0
        DEBUGMSGT(("9:cert:dump:names", "no subject name!\n"));
244
0
        return;
245
0
    }
246
247
0
    for (i = 0; i < X509_NAME_entry_count(osubj_name); i++) {
248
0
        oname_entry = X509_NAME_get_entry(osubj_name, i);
249
0
        netsnmp_assert(NULL != oname_entry);
250
0
        oname_value = X509_NAME_ENTRY_get_data(oname_entry);
251
252
0
        if (oname_value->type != V_ASN1_PRINTABLESTRING)
253
0
            continue;
254
255
        /** get NID */
256
0
        onid = OBJ_obj2nid(X509_NAME_ENTRY_get_object(oname_entry));
257
0
        if (onid == NID_undef) {
258
0
            prefix_long = prefix_short = "UNKNOWN";
259
0
        }
260
0
        else {
261
0
            prefix_long = OBJ_nid2ln(onid);
262
0
            prefix_short = OBJ_nid2sn(onid);
263
0
        }
264
265
0
        DEBUGMSGT(("9:cert:dump:names",
266
0
                   "[%02d] NID type %d, ASN type %d\n", i, onid,
267
0
                   oname_value->type));
268
0
        DEBUGMSGT(("9:cert:dump:names", "%s/%s: '%s'\n", prefix_long,
269
0
                   prefix_short, ASN1_STRING_get0_data(oname_value)));
270
0
    }
271
0
}
272
#endif /* NETSNMP_FEATURE_REMOVE_CERT_DUMP_NAMES */
273
274
static char *
275
_cert_get_extension(X509_EXTENSION  *oext, char **buf, int *len, int flags)
276
0
{
277
0
    int              space;
278
0
    char            *buf_ptr = NULL;
279
0
    u_char          *data;
280
0
    BIO             *bio;
281
    
282
0
    if ((NULL == oext) || ((buf && !len) || (len && !buf)))
283
0
        return NULL;
284
285
0
    bio = BIO_new(BIO_s_mem());
286
0
    if (NULL == bio) {
287
0
        snmp_log(LOG_ERR, "could not get bio for extension\n");
288
0
        return NULL;
289
0
    }
290
0
    if (X509V3_EXT_print(bio, oext, 0, 0) != 1) {
291
0
        snmp_log(LOG_ERR, "could not print extension!\n");
292
0
        goto out;
293
0
    }
294
295
0
    space = BIO_get_mem_data(bio, &data);
296
0
    if (buf && *buf) {
297
0
        if (*len < space + 1) {
298
0
            snmp_log(LOG_ERR, "not enough buffer space to print extension\n");
299
0
            goto out;
300
0
        }
301
0
        buf_ptr = *buf;
302
0
    } else {
303
0
        buf_ptr = calloc(1, space + 1);
304
0
    }
305
    
306
0
    if (!buf_ptr) {
307
0
        snmp_log(LOG_ERR, "error in allocation for extension\n");
308
0
        goto out;
309
0
    }
310
0
    memcpy(buf_ptr, data, space);
311
0
    buf_ptr[space] = 0;
312
0
    if (len)
313
0
        *len = space;
314
315
0
out:
316
0
    BIO_vfree(bio);
317
318
0
    return buf_ptr;
319
0
}
320
321
/** netsnmp_openssl_cert_get_extension: get extension field from cert
322
 * @internal
323
 */
324
/** instead of exposing this function, make helper functions for each
325
 * field, like netsnmp_openssl_cert_get_subjectAltName, below */
326
X509_EXTENSION  *
327
_cert_get_extension_at(X509 *ocert, int pos, char **buf, int *len, int flags)
328
0
{
329
0
    X509_EXTENSION  *oext;
330
331
0
    if ((NULL == ocert) || ((buf && !len) || (len && !buf)))
332
0
        return NULL;
333
334
0
    oext = X509_get_ext(ocert,pos);
335
0
    if (NULL == oext) {
336
0
        snmp_log(LOG_ERR, "extension number %d not found!\n", pos);
337
0
        netsnmp_openssl_cert_dump_extensions(ocert);
338
0
        return NULL;
339
0
    }
340
341
0
    return oext;
342
0
}
343
344
/** netsnmp_openssl_cert_get_extension: get extension field from cert
345
 * @internal
346
 */
347
/** instead of exposing this function, make helper functions for each
348
 * field, like netsnmp_openssl_cert_get_subjectAltName, below */
349
static char *
350
_cert_get_extension_str_at(X509 *ocert, int pos, char **buf, int *len,
351
                           int flags)
352
0
{
353
0
    X509_EXTENSION  *oext;
354
355
0
    if ((NULL == ocert) || ((buf && !len) || (len && !buf)))
356
0
        return NULL;
357
358
0
    oext = X509_get_ext(ocert,pos);
359
0
    if (NULL == oext) {
360
0
        snmp_log(LOG_ERR, "extension number %d not found!\n", pos);
361
0
        netsnmp_openssl_cert_dump_extensions(ocert);
362
0
        return NULL;
363
0
    }
364
365
0
    return _cert_get_extension(oext, buf, len, flags);
366
0
}
367
368
/** _cert_get_extension_id: get extension field from cert
369
 * @internal
370
 */
371
/** instead of exposing this function, make helper functions for each
372
 * field, like netsnmp_openssl_cert_get_subjectAltName, below */
373
X509_EXTENSION *
374
_cert_get_extension_id(X509 *ocert, int which, char **buf, int *len, int flags)
375
0
{
376
0
    int pos;
377
378
0
    if ((NULL == ocert) || ((buf && !len) || (len && !buf)))
379
0
        return NULL;
380
381
0
    pos = X509_get_ext_by_NID(ocert,which,-1);
382
0
    if (pos < 0) {
383
0
        DEBUGMSGT(("openssl:cert:name", "no extension %d\n", which));
384
0
        return NULL;
385
0
    }
386
387
0
    return _cert_get_extension_at(ocert, pos, buf, len, flags);
388
0
}
389
390
#ifndef NETSNMP_FEATURE_REMOVE_OPENSSL_CERT_GET_SUBJECTALTNAMES
391
/** _cert_get_extension_id_str: get extension field from cert
392
 * @internal
393
 */
394
/** instead of exposing this function, make helper functions for each
395
 * field, like netsnmp_openssl_cert_get_subjectAltName, below */
396
static char *
397
_cert_get_extension_id_str(X509 *ocert, int which, char **buf, int *len,
398
                           int flags)
399
0
{
400
0
    int pos;
401
402
0
    if ((NULL == ocert) || ((buf && !len) || (len && !buf)))
403
0
        return NULL;
404
405
0
    pos = X509_get_ext_by_NID(ocert,which,-1);
406
0
    if (pos < 0) {
407
0
        DEBUGMSGT(("openssl:cert:name", "no extension %d\n", which));
408
0
        return NULL;
409
0
    }
410
411
0
    return _cert_get_extension_str_at(ocert, pos, buf, len, flags);
412
0
}
413
#endif /* NETSNMP_FEATURE_REMOVE_OPENSSL_CERT_GET_SUBJECTALTNAMES */
414
415
static char *
416
_extract_oname(const GENERAL_NAME *oname)
417
0
{
418
0
    char  ipbuf[60], *buf = NULL, *rtn = NULL;
419
420
0
    if (NULL == oname)
421
0
        return NULL;
422
423
0
    switch ( oname->type ) {
424
0
        case GEN_EMAIL:
425
0
        case GEN_DNS:
426
            /*case GEN_URI:*/
427
0
            ASN1_STRING_to_UTF8((unsigned char**)&buf, oname->d.ia5);
428
0
            if (buf)
429
0
                rtn = strdup(buf);
430
0
            break;
431
432
0
        case GEN_IPADD:
433
0
            if (oname->d.iPAddress->length == 4) {
434
0
                sprintf(ipbuf, "%d.%d.%d.%d", oname->d.iPAddress->data[0],
435
0
                        oname->d.iPAddress->data[1],
436
0
                        oname->d.iPAddress->data[2],
437
0
                        oname->d.iPAddress->data[3]);
438
0
                rtn = strdup(ipbuf);
439
0
            }
440
0
            else if ((oname->d.iPAddress->length == 16) ||
441
0
                     (oname->d.iPAddress->length == 20)) {
442
0
                char *pos = ipbuf;
443
0
                int   j;
444
0
                for(j = 0; j < oname->d.iPAddress->length; ++j) {
445
0
                    *pos++ = VAL2HEX(oname->d.iPAddress->data[j]);
446
0
                    *pos++ = ':';
447
0
                }
448
0
                *pos = '\0';
449
0
                rtn = strdup(ipbuf);
450
0
            }
451
0
            else
452
0
                NETSNMP_LOGONCE((LOG_WARNING, "unexpected ip addr length %d\n",
453
0
                       oname->d.iPAddress->length));
454
455
0
            break;
456
0
        default:
457
0
            DEBUGMSGT(("openssl:cert:san", "unknown/unsupported type %d\n",
458
0
                       oname->type));
459
0
            break;
460
0
    }
461
0
    DEBUGMSGT(("9:openssl:cert:san", "san=%s\n", buf));
462
0
    if (buf)
463
0
        OPENSSL_free(buf);
464
465
0
    return rtn;
466
0
}
467
468
#ifndef NETSNMP_FEATURE_REMOVE_OPENSSL_CERT_GET_SUBJECTALTNAMES
469
/** netsnmp_openssl_cert_get_subjectAltName: get subjectAltName for cert.
470
 * if a pointer to a buffer and its length are specified, they will be
471
 * used. otherwise, a new buffer will be allocated, which the caller will
472
 * be responsbile for releasing.
473
 */
474
char *
475
netsnmp_openssl_cert_get_subjectAltNames(X509 *ocert, char **buf, int *len)
476
0
{
477
0
    return _cert_get_extension_id_str(ocert, NID_subject_alt_name, buf, len, 0);
478
0
}
479
#endif /* NETSNMP_FEATURE_REMOVE_OPENSSL_CERT_GET_SUBJECTALTNAMES */
480
481
void
482
netsnmp_openssl_cert_dump_extensions(X509 *ocert)
483
0
{
484
0
    X509_EXTENSION  *extension;
485
0
    const char      *extension_name;
486
0
    char             buf[SNMP_MAXBUF], *buf_ptr = buf, *str, *lf;
487
0
    int              i, num_extensions, buf_len, nid;
488
489
0
    if (NULL == ocert)
490
0
        return;
491
492
0
    DEBUGIF("9:cert:dump") 
493
0
        ;
494
0
    else
495
0
        return; /* bail if debug not enabled */
496
497
0
    num_extensions = X509_get_ext_count(ocert);
498
0
    if (0 == num_extensions)
499
0
        DEBUGMSGT(("9:cert:dump", "    0 extensions\n"));
500
0
    for(i = 0; i < num_extensions; i++) {
501
0
        extension = X509_get_ext(ocert, i);
502
0
        nid = OBJ_obj2nid(X509_EXTENSION_get_object(extension));
503
0
        extension_name = OBJ_nid2sn(nid);
504
0
        buf_len = sizeof(buf);
505
0
        str = _cert_get_extension_str_at(ocert, i, &buf_ptr, &buf_len, 0);
506
0
        if (!str) {
507
0
            DEBUGMSGT(("9:cert:dump", "    %2d: %s\n", i,
508
0
                        extension_name));
509
0
            continue;
510
0
        }
511
0
        lf = strchr(str, '\n'); /* look for multiline strings */
512
0
        if (NULL != lf)
513
0
            *lf = '\0'; /* only log first line of multiline here */
514
0
        DEBUGMSGT(("9:cert:dump", "    %2d: %s = %s\n", i,
515
0
                   extension_name, str));
516
0
        while(lf) { /* log remaining parts of multiline string */
517
0
            str = ++lf;
518
0
            if (*str == '\0')
519
0
               break;
520
0
            lf = strchr(str, '\n');
521
0
            if (NULL == lf) 
522
0
                break;
523
0
            *lf = '\0';
524
0
            DEBUGMSGT(("9:cert:dump", "        %s\n", str));
525
0
        }
526
0
    }
527
0
}
528
529
static const struct {
530
    uint16_t nid;
531
    uint16_t ht;
532
} _htmap[] = {
533
    { 0, NS_HASH_NONE },
534
#ifdef NID_md5WithRSAEncryption
535
    { NID_md5WithRSAEncryption, NS_HASH_MD5 },
536
#endif
537
#ifdef NID_sha1WithRSAEncryption
538
    { NID_sha1WithRSAEncryption, NS_HASH_SHA1 },
539
#endif
540
#ifdef NID_ecdsa_with_SHA1
541
    { NID_ecdsa_with_SHA1, NS_HASH_SHA1 },
542
#endif
543
#ifdef NID_sha224WithRSAEncryption
544
    { NID_sha224WithRSAEncryption, NS_HASH_SHA224 },
545
#endif
546
#ifdef NID_ecdsa_with_SHA224
547
    { NID_ecdsa_with_SHA224, NS_HASH_SHA224 },
548
#endif
549
#ifdef NID_sha256WithRSAEncryption
550
    { NID_sha256WithRSAEncryption, NS_HASH_SHA256 },
551
#endif
552
#ifdef NID_ecdsa_with_SHA256
553
    { NID_ecdsa_with_SHA256, NS_HASH_SHA256 },
554
#endif
555
#ifdef NID_sha384WithRSAEncryption
556
    { NID_sha384WithRSAEncryption, NS_HASH_SHA384 },
557
#endif
558
#ifdef NID_ecdsa_with_SHA384
559
    { NID_ecdsa_with_SHA384, NS_HASH_SHA384 },
560
#endif
561
#ifdef NID_sha512WithRSAEncryption
562
    { NID_sha512WithRSAEncryption, NS_HASH_SHA512 },
563
#endif
564
#ifdef NID_ecdsa_with_SHA512
565
    { NID_ecdsa_with_SHA512, NS_HASH_SHA512 },
566
#endif
567
};
568
569
int
570
_nid2ht(int nid)
571
0
{
572
0
    int i;
573
574
0
    for (i = 0; i < sizeof(_htmap) / sizeof(_htmap[0]); i++) {
575
0
        if (_htmap[i].nid == nid)
576
0
            return _htmap[i].ht;
577
0
    }
578
0
    return 0;
579
0
}
580
581
#ifndef NETSNMP_FEATURE_REMOVE_OPENSSL_HT2NID
582
int
583
_ht2nid(int ht)
584
0
{
585
0
    int i;
586
587
0
    for (i = 0; i < sizeof(_htmap) / sizeof(_htmap[0]); i++) {
588
0
        if (_htmap[i].ht == ht)
589
0
            return _htmap[i].nid;
590
0
    }
591
0
    return 0;
592
0
}
593
#endif /* NETSNMP_FEATURE_REMOVE_OPENSSL_HT2NID */
594
595
/**
596
 * returns allocated pointer caller must free.
597
 */
598
int
599
netsnmp_openssl_cert_get_hash_type(X509 *ocert)
600
0
{
601
0
    if (NULL == ocert)
602
0
        return 0;
603
604
0
    return _nid2ht(X509_get_signature_nid(ocert));
605
0
}
606
607
/**
608
 * returns allocated pointer caller must free.
609
 */
610
char *
611
netsnmp_openssl_cert_get_fingerprint(X509 *ocert, int alg)
612
0
{
613
0
    u_char           fingerprint[EVP_MAX_MD_SIZE];
614
0
    u_int            fingerprint_len, nid;
615
0
    const EVP_MD    *digest;
616
0
    char            *result = NULL;
617
618
0
    if (NULL == ocert)
619
0
        return NULL;
620
621
0
    nid = X509_get_signature_nid(ocert);
622
0
    DEBUGMSGT(("9:openssl:fingerprint", "alg %d, cert nid %d (%d)\n", alg, nid,
623
0
               _nid2ht(nid)));
624
        
625
0
    if ((-1 == alg) && nid)
626
0
        alg = _nid2ht(nid);
627
628
0
    switch (alg) {
629
0
        case NS_HASH_MD5:
630
0
            snmp_log(LOG_ERR, "hash type md5 not yet supported\n");
631
0
            return NULL;
632
0
            break;
633
        
634
0
        case NS_HASH_NONE:
635
0
            snmp_log(LOG_ERR, "hash type none not supported. using SHA1\n");
636
0
            NETSNMP_FALLTHROUGH;
637
638
0
        case NS_HASH_SHA1:
639
0
            digest = EVP_sha1();
640
0
            break;
641
642
0
#ifdef HAVE_EVP_SHA224
643
0
        case NS_HASH_SHA224:
644
0
            digest = EVP_sha224();
645
0
            break;
646
647
0
        case NS_HASH_SHA256:
648
0
            digest = EVP_sha256();
649
0
            break;
650
651
0
#endif
652
0
#ifdef HAVE_EVP_SHA384
653
0
        case NS_HASH_SHA384:
654
0
            digest = EVP_sha384();
655
0
            break;
656
657
0
        case NS_HASH_SHA512:
658
0
            digest = EVP_sha512();
659
0
            break;
660
0
#endif
661
662
0
        default:
663
0
            snmp_log(LOG_ERR, "unknown hash algorithm %d\n", alg);
664
0
            return NULL;
665
0
    }
666
667
0
    if (_nid2ht(nid) != alg) {
668
0
        DEBUGMSGT(("openssl:fingerprint",
669
0
                   "WARNING: alg %d does not match cert alg %d\n",
670
0
                   alg, _nid2ht(nid)));
671
0
    }
672
0
    if (X509_digest(ocert,digest,fingerprint,&fingerprint_len)) {
673
0
        binary_to_hex(fingerprint, fingerprint_len, &result);
674
0
        if (NULL == result)
675
0
            snmp_log(LOG_ERR, "failed to hexify fingerprint\n");
676
0
        else
677
0
            DEBUGMSGT(("9:openssl:fingerprint", "fingerprint %s\n", result));
678
0
    }
679
0
    else
680
0
        snmp_log(LOG_ERR,"failed to compute fingerprint\n");
681
682
0
    return result;
683
0
}
684
685
/**
686
 * get container of netsnmp_cert_map structures from an ssl connection
687
 * certificate chain.
688
 */
689
netsnmp_container *
690
netsnmp_openssl_get_cert_chain(SSL *ssl)
691
0
{
692
0
    X509                  *ocert, *ocert_tmp;
693
0
    STACK_OF(X509)        *ochain;
694
0
    char                  *fingerprint;
695
0
    netsnmp_container     *chain_map;
696
0
    netsnmp_cert_map      *cert_map;
697
0
    int                    i, sk_num_res;
698
699
0
    netsnmp_assert_or_return(ssl != NULL, NULL);
700
701
0
    ocert = SSL_get_peer_certificate(ssl);
702
0
    if (!ocert) {
703
        /** no peer cert */
704
0
        snmp_log(LOG_ERR, "SSL peer has no certificate\n");
705
0
        return NULL;
706
0
    }
707
0
    DEBUGIF("9:cert:dump") {
708
0
        netsnmp_openssl_cert_dump_extensions(ocert);
709
0
    }
710
711
    /*
712
     * get fingerprint and save it
713
     */
714
0
    fingerprint = netsnmp_openssl_cert_get_fingerprint(ocert, -1);
715
0
    if (NULL == fingerprint)
716
0
        return NULL;
717
718
    /*
719
     * allocate cert map. Don't pass in fingerprint, since it would strdup
720
     * it and we've already got a copy.
721
     */
722
0
    cert_map = netsnmp_cert_map_alloc(NULL, ocert);
723
0
    if (NULL == cert_map) {
724
0
        free(fingerprint);
725
0
        return NULL;
726
0
    }
727
0
    cert_map->fingerprint = fingerprint;
728
0
    cert_map->hashType = netsnmp_openssl_cert_get_hash_type(ocert);
729
730
0
    chain_map = netsnmp_cert_map_container_create(0); /* no fp subcontainer */
731
0
    if (NULL == chain_map) {
732
0
        netsnmp_cert_map_free(cert_map);
733
0
        return NULL;
734
0
    }
735
    
736
0
    CONTAINER_INSERT(chain_map, cert_map);
737
738
    /** check for a chain to a CA */
739
0
    ochain = SSL_get_peer_cert_chain(ssl);
740
0
    sk_num_res = sk_X509_num(ochain);
741
0
    if (!ochain || sk_num_res == 0) {
742
0
        DEBUGMSGT(("ssl:cert:chain", "peer has no cert chain\n"));
743
0
    }
744
0
    else {
745
        /*
746
         * loop over chain, adding fingerprint / cert for each
747
         */
748
0
        DEBUGMSGT(("ssl:cert:chain", "examining cert chain\n"));
749
0
        sk_num_res = sk_X509_num(ochain);
750
0
        for(i = 0; i < sk_num_res; ++i) {
751
0
            ocert_tmp = sk_X509_value(ochain, i);
752
0
            fingerprint = netsnmp_openssl_cert_get_fingerprint(ocert_tmp, -1);
753
0
            if (NULL == fingerprint)
754
0
                break;
755
0
            cert_map = netsnmp_cert_map_alloc(NULL, ocert);
756
0
            if (NULL == cert_map) {
757
0
                free(fingerprint);
758
0
                break;
759
0
            }
760
0
            cert_map->fingerprint = fingerprint;
761
0
            cert_map->hashType = netsnmp_openssl_cert_get_hash_type(ocert_tmp);
762
763
0
            CONTAINER_INSERT(chain_map, cert_map);
764
0
        } /* chain loop */
765
        /*
766
         * if we broke out of loop before finishing, clean up
767
         */
768
0
        if (i < sk_num_res)
769
0
            CONTAINER_FREE_ALL(chain_map, NULL);
770
0
    } /* got peer chain */
771
772
0
    DEBUGMSGT(("ssl:cert:chain", "found %" NETSNMP_PRIz "u certs in chain\n",
773
0
               CONTAINER_SIZE(chain_map)));
774
0
    if (CONTAINER_SIZE(chain_map) == 0) {
775
0
        CONTAINER_FREE(chain_map);
776
0
        chain_map = NULL;
777
0
    }
778
779
0
    return chain_map;
780
0
}
781
782
/*
783
tlstmCertSANRFC822Name "Maps a subjectAltName's rfc822Name to a
784
                  tmSecurityName.  The local part of the rfc822Name is
785
                  passed unaltered but the host-part of the name must
786
                  be passed in lower case.
787
                  Example rfc822Name Field:  FooBar@Example.COM
788
                  is mapped to tmSecurityName: FooBar@example.com"
789
790
tlstmCertSANDNSName "Maps a subjectAltName's dNSName to a
791
                  tmSecurityName after first converting it to all
792
                  lower case."
793
794
tlstmCertSANIpAddress "Maps a subjectAltName's iPAddress to a
795
                  tmSecurityName by transforming the binary encoded
796
                  address as follows:
797
                  1) for IPv4 the value is converted into a decimal
798
                     dotted quad address (e.g. '192.0.2.1')
799
                  2) for IPv6 addresses the value is converted into a
800
                     32-character all lowercase hexadecimal string
801
                     without any colon separators.
802
803
                     Note that the resulting length is the maximum
804
                     length supported by the View-Based Access Control
805
                     Model (VACM).  Note that using both the Transport
806
                     Security Model's support for transport prefixes
807
                     (see the SNMP-TSM-MIB's
808
                     snmpTsmConfigurationUsePrefix object for details)
809
                     will result in securityName lengths that exceed
810
                     what VACM can handle."
811
812
tlstmCertSANAny "Maps any of the following fields using the
813
                  corresponding mapping algorithms:
814
                  | rfc822Name | tlstmCertSANRFC822Name |
815
                  | dNSName    | tlstmCertSANDNSName    |
816
                  | iPAddress  | tlstmCertSANIpAddress  |
817
                  The first matching subjectAltName value found in the
818
                  certificate of the above types MUST be used when
819
                  deriving the tmSecurityName."
820
*/
821
char *
822
_cert_get_san_type(X509 *ocert, int mapType)
823
0
{
824
0
    GENERAL_NAMES      *onames;
825
0
    const GENERAL_NAME *oname = NULL;
826
0
    char               *buf = NULL, *lower = NULL;
827
0
    int                 count, i;
828
 
829
0
    onames = (GENERAL_NAMES *)X509_get_ext_d2i(ocert, NID_subject_alt_name,
830
0
                                               NULL, NULL );
831
0
    if (NULL == onames)
832
0
        return NULL;
833
834
0
    count = sk_GENERAL_NAME_num(onames);
835
836
0
    for (i=0 ; i <count; ++i)  {
837
0
        oname = sk_GENERAL_NAME_value(onames, i);
838
839
0
        if (GEN_DNS == oname->type) {
840
0
            if ((TSNM_tlstmCertSANDNSName == mapType) ||
841
0
                (TSNM_tlstmCertSANAny == mapType)) {
842
0
                lower = buf = _extract_oname( oname );
843
0
                break;
844
0
            }
845
0
        }
846
0
        else if (GEN_IPADD == oname->type) {
847
0
            if ((TSNM_tlstmCertSANIpAddress == mapType) ||
848
0
                (TSNM_tlstmCertSANAny == mapType)) {
849
0
                buf = _extract_oname(oname);
850
0
                break;
851
0
            }
852
0
        }
853
0
        else if (GEN_EMAIL == oname->type) {
854
0
            if ((TSNM_tlstmCertSANRFC822Name == mapType) ||
855
0
                (TSNM_tlstmCertSANAny == mapType)) {
856
0
                buf = _extract_oname(oname);
857
0
                lower = strchr(buf, '@');
858
0
                if (NULL == lower) {
859
0
                    DEBUGMSGT(("openssl:secname:extract",
860
0
                               "email %s has no '@'!\n", buf));
861
0
                }
862
0
                else {
863
0
                    ++lower;
864
0
                    break;
865
0
                }
866
0
            }
867
            
868
0
        }
869
0
    } /* for loop */
870
871
0
    if (lower)
872
0
        for ( ; *lower; ++lower )
873
0
            *lower = tolower(0xFF & *lower);
874
0
    DEBUGMSGT(("openssl:cert:extension:san", "#%d type %d: %s\n", i,
875
0
               oname ? oname->type : -1, buf ? buf : "NULL"));
876
877
0
    return buf;
878
0
}
879
880
char *
881
netsnmp_openssl_extract_secname(netsnmp_cert_map *cert_map,
882
                                netsnmp_cert_map *peer_cert)
883
0
{
884
0
    char       *rtn = NULL;
885
886
0
    if (NULL == cert_map)
887
0
        return NULL;
888
889
0
    DEBUGMSGT(("openssl:secname:extract",
890
0
               "checking priority %d, san of type %d for %s\n",
891
0
               cert_map->priority, cert_map->mapType, peer_cert->fingerprint));
892
893
0
    switch(cert_map->mapType) {
894
0
        case TSNM_tlstmCertSpecified:
895
0
            rtn = strdup(cert_map->data);
896
0
            break;
897
898
0
        case TSNM_tlstmCertSANRFC822Name:
899
0
        case TSNM_tlstmCertSANDNSName:
900
0
        case TSNM_tlstmCertSANIpAddress:
901
0
        case TSNM_tlstmCertSANAny:
902
0
            if (NULL == peer_cert) {
903
0
                DEBUGMSGT(("openssl:secname:extract", "no peer cert for %s\n",
904
0
                           cert_map->fingerprint));
905
0
                break;
906
0
            }
907
0
            rtn = _cert_get_san_type(peer_cert->ocert, cert_map->mapType);
908
0
            if (NULL == rtn) {
909
0
                DEBUGMSGT(("openssl:secname:extract", "no san for %s\n",
910
0
                           peer_cert->fingerprint));
911
0
            }
912
0
            break;
913
914
0
        case TSNM_tlstmCertCommonName:
915
0
            rtn = netsnmp_openssl_cert_get_commonName(cert_map->ocert, NULL,
916
0
                                                       NULL);
917
0
            break;
918
0
        default:
919
0
            snmp_log(LOG_ERR, "cant extract secname for unknown map type %d\n",
920
0
                     cert_map->mapType);
921
0
            break;
922
0
    } /* switch mapType */
923
924
0
    if (rtn) {
925
0
        DEBUGMSGT(("openssl:secname:extract",
926
0
                   "found map %d, type %d for %s: %s\n", cert_map->priority,
927
0
                   cert_map->mapType, peer_cert->fingerprint, rtn));
928
0
        if (strlen(rtn) >32) {
929
0
            DEBUGMSGT(("openssl:secname:extract",
930
0
                       "secName longer than 32 chars! dropping...\n"));
931
0
            SNMP_FREE(rtn);
932
0
        }
933
0
    }
934
0
    else
935
0
        DEBUGMSGT(("openssl:secname:extract",
936
0
                   "no map of type %d for %s\n",
937
0
                   cert_map->mapType, peer_cert->fingerprint));
938
0
    return rtn;
939
0
}
940
941
int
942
netsnmp_openssl_cert_issued_by(X509 *issuer, X509 *cert)
943
0
{
944
0
    return (X509_check_issued(issuer, cert) == X509_V_OK);
945
0
}
946
947
948
void
949
netsnmp_openssl_null_checks(SSL *ssl, int *null_auth, int *null_cipher)
950
0
{
951
0
    const SSL_CIPHER *cipher;
952
0
    char           tmp_buf[128], *cipher_alg, *auth_alg;
953
954
0
    if (null_auth)
955
0
        *null_auth = -1; /* unknown */
956
0
    if (null_cipher)
957
0
        *null_cipher = -1; /* unknown */
958
0
    if (NULL == ssl)
959
0
        return;
960
961
0
    cipher = SSL_get_current_cipher(ssl);
962
0
    if (NULL == cipher) {
963
0
        DEBUGMSGTL(("ssl:cipher", "no cipher yet\n"));
964
0
        return;
965
0
    }
966
0
    SSL_CIPHER_description(NETSNMP_REMOVE_CONST(SSL_CIPHER *, cipher), tmp_buf, sizeof(tmp_buf));
967
    /** no \n since tmp_buf already has one */
968
0
    DEBUGMSGTL(("ssl:cipher", "current cipher: %s", tmp_buf));
969
970
    /*
971
     * run "openssl ciphers -v eNULL" and "openssl ciphers -v aNULL"
972
     * to see NULL encryption/authentication algorithms. e.g.
973
     *
974
     * EXP-ADH-RC4-MD5 SSLv3 Kx=DH(512) Au=None Enc=RC4(40) Mac=MD5  export
975
     * NULL-SHA        SSLv3 Kx=RSA     Au=RSA  Enc=None    Mac=SHA1
976
     */
977
0
    if (null_cipher) {
978
0
        cipher_alg = strstr(tmp_buf, "Enc=");
979
0
        if (cipher_alg) {
980
0
            cipher_alg += 4;
981
0
            if (strncmp(cipher_alg,"None", 4) == 0)
982
0
                *null_cipher = 1;
983
0
            else
984
0
                *null_cipher = 0;
985
0
        }
986
0
    }
987
0
    if (null_auth) {
988
0
        auth_alg = strstr(tmp_buf, "Au=");
989
0
        if (auth_alg) {
990
0
            auth_alg += 3;
991
0
            if (strncmp(auth_alg,"None", 4) == 0)
992
0
                *null_auth = 1;
993
0
            else
994
0
                *null_auth = 0;
995
0
        }
996
0
    }
997
0
}
998
999
#ifndef HAVE_X509_GET_SIGNATURE_NID
1000
int X509_get_signature_nid(const X509 *x)
1001
{
1002
    return OBJ_obj2nid(x->sig_alg->algorithm);
1003
}
1004
#endif
1005
1006
#ifndef HAVE_ASN1_STRING_GET0_DATA
1007
const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *x)
1008
{
1009
    return x->data;
1010
}
1011
#endif
1012
1013
#ifndef HAVE_X509_NAME_ENTRY_GET_OBJECT
1014
ASN1_OBJECT *X509_NAME_ENTRY_get_object(const X509_NAME_ENTRY *ne)
1015
{
1016
    if (ne == NULL)
1017
        return NULL;
1018
    return ne->object;
1019
}
1020
#endif
1021
1022
#ifndef HAVE_X509_NAME_ENTRY_GET_DATA
1023
ASN1_STRING *X509_NAME_ENTRY_get_data(const X509_NAME_ENTRY *ne)
1024
{
1025
    if (ne == NULL)
1026
        return NULL;
1027
    return ne->value;
1028
}
1029
#endif
1030
1031
#ifndef HAVE_TLS_METHOD
1032
const SSL_METHOD *TLS_method(void)
1033
{
1034
    return TLSv1_method();
1035
}
1036
#endif
1037
1038
#ifndef HAVE_DTLS_METHOD
1039
const SSL_METHOD *DTLS_method(void)
1040
{
1041
    return DTLSv1_method();
1042
}
1043
#endif
1044
1045
#endif /* NETSNMP_USE_OPENSSL && HAVE_LIBSSL && !defined(NETSNMP_FEATURE_REMOVE_CERT_UTIL) */