~ubuntu-branches/debian/sid/postfix/sid

« back to all changes in this revision

Viewing changes to src/tls/tls_fprint.c

  • Committer: Package Import Robot
  • Author(s): LaMont Jones, LaMont Jones, localization folks
  • Date: 2014-02-11 07:44:30 UTC
  • mfrom: (1.1.41)
  • Revision ID: package-import@ubuntu.com-20140211074430-91tdwgjriazawdz4
Tags: 2.11.0-1
[LaMont Jones]

* New upstream release: 2.11.0

[localization folks]

* l10n: Updated German translations.  Closes: #734893 (Helge Kreutzmann)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*++
 
2
/* NAME
 
3
/*      tls_fprint 3
 
4
/* SUMMARY
 
5
/*      Digests fingerprints and all that.
 
6
/* SYNOPSIS
 
7
/*      #include <tls.h>
 
8
/*
 
9
/*      char    *tls_serverid_digest(props, protomask, ciphers)
 
10
/*      const TLS_CLIENT_START_PROPS *props;
 
11
/*      long    protomask;
 
12
/*      const char *ciphers;
 
13
/*
 
14
/*      char    *tls_digest_encode(md_buf, md_len)
 
15
/*      const unsigned char *md_buf;
 
16
/*      const char *md_len;
 
17
/*
 
18
/*      char    *tls_data_fprint(buf, len, mdalg)
 
19
/*      const char *buf;
 
20
/*      int     len;
 
21
/*      const char *mdalg;
 
22
/*
 
23
/*      char    *tls_cert_fprint(peercert, mdalg)
 
24
/*      X509    *peercert;
 
25
/*      const char *mdalg;
 
26
/*
 
27
/*      char    *tls_pkey_fprint(peercert, mdalg)
 
28
/*      X509    *peercert;
 
29
/*      const char *mdalg;
 
30
/* DESCRIPTION
 
31
/*      tls_digest_encode() converts a binary message digest to a hex ASCII
 
32
/*      format with ':' separators between each pair of hex digits.
 
33
/*      The return value is dynamically allocated with mymalloc(),
 
34
/*      and the caller must eventually free it with myfree().
 
35
/*
 
36
/*      tls_data_fprint() digests unstructured data, and encodes the digested
 
37
/*      result via tls_digest_encode().  The return value is dynamically
 
38
/*      allocated with mymalloc(), and the caller must eventually free it
 
39
/*      with myfree().
 
40
/*
 
41
/*      tls_cert_fprint() returns a fingerprint of the the given
 
42
/*      certificate using the requested message digest, formatted
 
43
/*      with tls_digest_encode(). Panics if the
 
44
/*      (previously verified) digest algorithm is not found. The return
 
45
/*      value is dynamically allocated with mymalloc(), and the caller
 
46
/*      must eventually free it with myfree().
 
47
/*
 
48
/*      tls_pkey_fprint() returns a public-key fingerprint; in all
 
49
/*      other respects the function behaves as tls_cert_fprint().
 
50
/*      The var_tls_bc_pkey_fprint variable enables an incorrect
 
51
/*      algorithm that was used in Postfix versions 2.9.[0-5].
 
52
/*      The return value is dynamically allocated with mymalloc(),
 
53
/*      and the caller must eventually free it with myfree().
 
54
/*
 
55
/*      tls_serverid_digest() suffixes props->serverid computed by the SMTP
 
56
/*      client with "&" plus a digest of additional parameters
 
57
/*      needed to ensure that re-used sessions are more likely to
 
58
/*      be reused and that they will satisfy all protocol and
 
59
/*      security requirements.
 
60
/*      The return value is dynamically allocated with mymalloc(),
 
61
/*      and the caller must eventually free it with myfree().
 
62
/*
 
63
/*      Arguments:
 
64
/* .IP peercert
 
65
/*      Server or client X.509 certificate.
 
66
/* .IP md_buf
 
67
/*      The raw binary digest.
 
68
/* .IP md_len
 
69
/*      The digest length in bytes.
 
70
/* .IP mdalg
 
71
/*      Name of a message digest algorithm suitable for computing secure
 
72
/*      (1st pre-image resistant) message digests of certificates. For now,
 
73
/*      md5, sha1, or member of SHA-2 family if supported by OpenSSL.
 
74
/* .IP buf
 
75
/*      Input data for the message digest algorithm mdalg.
 
76
/* .IP len
 
77
/*      The length of the input data.
 
78
/* .IP props
 
79
/*      The client start properties for the session, which contains the
 
80
/*      initial serverid from the SMTP client and the DANE verification
 
81
/*      parameters.
 
82
/* .IP protomask
 
83
/*      The mask of protocol exclusions.
 
84
/* .IP ciphers
 
85
/*      The SSL client cipherlist.
 
86
/* LICENSE
 
87
/* .ad
 
88
/* .fi
 
89
/*      This software is free. You can do with it whatever you want.
 
90
/*      The original author kindly requests that you acknowledge
 
91
/*      the use of his software.
 
92
/* AUTHOR(S)
 
93
/*      Wietse Venema
 
94
/*      IBM T.J. Watson Research
 
95
/*      P.O. Box 704
 
96
/*      Yorktown Heights, NY 10598, USA
 
97
/*
 
98
/*      Viktor Dukhovni
 
99
/*--*/
 
100
 
 
101
/* System library. */
 
102
 
 
103
#include <sys_defs.h>
 
104
#include <ctype.h>
 
105
 
 
106
#ifdef USE_TLS
 
107
#include <string.h>
 
108
 
 
109
/* Utility library. */
 
110
 
 
111
#include <msg.h>
 
112
#include <mymalloc.h>
 
113
#include <stringops.h>
 
114
 
 
115
/* Global library. */
 
116
 
 
117
#include <mail_params.h>
 
118
 
 
119
/* TLS library. */
 
120
 
 
121
#define TLS_INTERNAL
 
122
#include <tls.h>
 
123
 
 
124
/* Application-specific. */
 
125
 
 
126
static const char hexcodes[] = "0123456789ABCDEF";
 
127
 
 
128
#define checkok(ret)    (ok &= ((ret) ? 1 : 0))
 
129
#define digest_data(p, l) checkok(EVP_DigestUpdate(mdctx, (char *)(p), (l)))
 
130
#define digest_object(p) digest_data((p), sizeof(*(p)))
 
131
#define digest_string(s) digest_data((s), strlen(s)+1)
 
132
 
 
133
#define digest_dane(dane, memb) do { \
 
134
        if ((dane)->memb != 0) \
 
135
            checkok(digest_tlsa_usage(mdctx, (dane)->memb, #memb)); \
 
136
    } while (0)
 
137
 
 
138
#define digest_tlsa_argv(tlsa, memb) do { \
 
139
        if ((tlsa)->memb) { \
 
140
            digest_string(#memb); \
 
141
            for (dgst = (tlsa)->memb->argv; *dgst; ++dgst) \
 
142
                digest_string(*dgst); \
 
143
        } \
 
144
    } while (0)
 
145
 
 
146
/* digest_tlsa_usage - digest TA or EE match list sorted by alg and value */
 
147
 
 
148
static int digest_tlsa_usage(EVP_MD_CTX * mdctx, TLS_TLSA *tlsa,
 
149
                                     const char *usage)
 
150
{
 
151
    char  **dgst;
 
152
    int     ok = 1;
 
153
 
 
154
    for (digest_string(usage); tlsa; tlsa = tlsa->next) {
 
155
        digest_string(tlsa->mdalg);
 
156
        digest_tlsa_argv(tlsa, pkeys);
 
157
        digest_tlsa_argv(tlsa, certs);
 
158
    }
 
159
    return (ok);
 
160
}
 
161
 
 
162
/* tls_serverid_digest - suffix props->serverid with parameter digest */
 
163
 
 
164
char   *tls_serverid_digest(const TLS_CLIENT_START_PROPS *props, long protomask,
 
165
                                    const char *ciphers)
 
166
{
 
167
    EVP_MD_CTX *mdctx;
 
168
    const EVP_MD *md;
 
169
    const char *mdalg;
 
170
    unsigned char md_buf[EVP_MAX_MD_SIZE];
 
171
    unsigned int md_len;
 
172
    int     ok = 1;
 
173
    int     i;
 
174
    long    sslversion;
 
175
    VSTRING *result;
 
176
 
 
177
    /*
 
178
     * Try to use sha256: our serverid choice should be strong enough to
 
179
     * resist 2nd-preimage attacks with a difficulty comparable to that of
 
180
     * DANE TLSA digests.  Failing that, we compute serverid digests with the
 
181
     * default digest, but DANE requires sha256 and sha512, so if we must
 
182
     * fall back to our default digest, DANE support won't be available.  We
 
183
     * panic if the fallback algorithm is not available, as it was verified
 
184
     * available in tls_client_init() and must not simply vanish.
 
185
     */
 
186
    if ((md = EVP_get_digestbyname(mdalg = "sha256")) == 0
 
187
        && (md = EVP_get_digestbyname(mdalg = props->mdalg)) == 0)
 
188
        msg_panic("digest algorithm \"%s\" not found", mdalg);
 
189
 
 
190
    /* Salt the session lookup key with the OpenSSL runtime version. */
 
191
    sslversion = SSLeay();
 
192
 
 
193
    mdctx = EVP_MD_CTX_create();
 
194
    checkok(EVP_DigestInit_ex(mdctx, md, NULL));
 
195
    digest_string(props->helo ? props->helo : "");
 
196
    digest_object(&sslversion);
 
197
    digest_object(&protomask);
 
198
    digest_string(ciphers);
 
199
 
 
200
    /*
 
201
     * All we get from the session cache is a single bit telling us whether
 
202
     * the certificate is trusted or not, but we need to know whether the
 
203
     * trust is CA-based (in that case we must do name checks) or whether it
 
204
     * is a direct end-point match.  We mustn't confuse the two, so it is
 
205
     * best to process only TA trust in the verify callback and check the EE
 
206
     * trust after. This works since re-used sessions always have access to
 
207
     * the leaf certificate, while only the original session has the leaf and
 
208
     * the full trust chain.
 
209
     * 
 
210
     * Only the trust anchor matchlist is hashed into the session key. The end
 
211
     * entity certs are not used to determine whether a certificate is
 
212
     * trusted or not, rather these are rechecked against the leaf cert
 
213
     * outside the verification callback, each time a session is created or
 
214
     * reused.
 
215
     * 
 
216
     * Therefore, the security context of the session does not depend on the EE
 
217
     * matching data, which is checked separately each time.  So we exclude
 
218
     * the EE part of the DANE structure from the serverid digest.
 
219
     * 
 
220
     * If the security level is "dane", we send SNI information to the peer.
 
221
     * This may cause it to respond with a non-default certificate.  Since
 
222
     * certificates for sessions with no or different SNI data may not match,
 
223
     * we must include the SNI name in the session id.
 
224
     */
 
225
    if (props->dane) {
 
226
        digest_dane(props->dane, ta);
 
227
#if 0
 
228
        digest_dane(props->dane, ee);           /* See above */
 
229
#endif
 
230
        digest_string(props->tls_level == TLS_LEV_DANE ? props->host : "");
 
231
    }
 
232
    checkok(EVP_DigestFinal_ex(mdctx, md_buf, &md_len));
 
233
    EVP_MD_CTX_destroy(mdctx);
 
234
    if (!ok)
 
235
        msg_fatal("error computing %s message digest", mdalg);
 
236
 
 
237
    /* Check for OpenSSL contract violation */
 
238
    if (md_len > EVP_MAX_MD_SIZE)
 
239
        msg_panic("unexpectedly large %s digest size: %u", mdalg, md_len);
 
240
 
 
241
    /*
 
242
     * Append the digest to the serverid.  We don't compare this digest to
 
243
     * any user-specified fingerprints.  Therefore, we don't need to use a
 
244
     * colon-separated format, which saves space in the TLS session cache and
 
245
     * makes logging of session cache lookup keys more readable.
 
246
     * 
 
247
     * This does however duplicate a few lines of code from the digest encoder
 
248
     * for colon-separated cert and pkey fingerprints. If that is a
 
249
     * compelling reason to consolidate, we could use that and append the
 
250
     * result.
 
251
     */
 
252
    result = vstring_alloc(strlen(props->serverid) + 1 + 2 * md_len);
 
253
    vstring_strcpy(result, props->serverid);
 
254
    VSTRING_ADDCH(result, '&');
 
255
    for (i = 0; i < md_len; i++) {
 
256
        VSTRING_ADDCH(result, hexcodes[(md_buf[i] & 0xf0) >> 4U]);
 
257
        VSTRING_ADDCH(result, hexcodes[(md_buf[i] & 0x0f)]);
 
258
    }
 
259
    VSTRING_TERMINATE(result);
 
260
    return (vstring_export(result));
 
261
}
 
262
 
 
263
/* tls_digest_encode - encode message digest binary blob as xx:xx:... */
 
264
 
 
265
char   *tls_digest_encode(const unsigned char *md_buf, int md_len)
 
266
{
 
267
    int     i;
 
268
    char   *result = mymalloc(md_len * 3);
 
269
 
 
270
    /* Check for contract violation */
 
271
    if (md_len > EVP_MAX_MD_SIZE || md_len >= INT_MAX / 3)
 
272
        msg_panic("unexpectedly large message digest size: %u", md_len);
 
273
 
 
274
    /* No risk of overrunes, len is bounded by OpenSSL digest length */
 
275
    for (i = 0; i < md_len; i++) {
 
276
        result[i * 3] = hexcodes[(md_buf[i] & 0xf0) >> 4U];
 
277
        result[(i * 3) + 1] = hexcodes[(md_buf[i] & 0x0f)];
 
278
        result[(i * 3) + 2] = (i + 1 != md_len) ? ':' : '\0';
 
279
    }
 
280
    return (result);
 
281
}
 
282
 
 
283
/* tls_data_fprint - compute and encode digest of binary object */
 
284
 
 
285
char   *tls_data_fprint(const char *buf, int len, const char *mdalg)
 
286
{
 
287
    EVP_MD_CTX *mdctx;
 
288
    const EVP_MD *md;
 
289
    unsigned char md_buf[EVP_MAX_MD_SIZE];
 
290
    unsigned int md_len;
 
291
    int     ok = 1;
 
292
 
 
293
    /* Previously available in "init" routine. */
 
294
    if ((md = EVP_get_digestbyname(mdalg)) == 0)
 
295
        msg_panic("digest algorithm \"%s\" not found", mdalg);
 
296
 
 
297
    mdctx = EVP_MD_CTX_create();
 
298
    checkok(EVP_DigestInit_ex(mdctx, md, NULL));
 
299
    digest_data(buf, len);
 
300
    checkok(EVP_DigestFinal_ex(mdctx, md_buf, &md_len));
 
301
    EVP_MD_CTX_destroy(mdctx);
 
302
    if (!ok)
 
303
        msg_fatal("error computing %s message digest", mdalg);
 
304
 
 
305
    return (tls_digest_encode(md_buf, md_len));
 
306
}
 
307
 
 
308
/* tls_cert_fprint - extract certificate fingerprint */
 
309
 
 
310
char   *tls_cert_fprint(X509 *peercert, const char *mdalg)
 
311
{
 
312
    int     len;
 
313
    char   *buf;
 
314
    char   *buf2;
 
315
    char   *result;
 
316
 
 
317
    len = i2d_X509(peercert, NULL);
 
318
    buf2 = buf = mymalloc(len);
 
319
    i2d_X509(peercert, (unsigned char **) &buf2);
 
320
    if (buf2 - buf != len)
 
321
        msg_panic("i2d_X509 invalid result length");
 
322
 
 
323
    result = tls_data_fprint(buf, len, mdalg);
 
324
    myfree(buf);
 
325
 
 
326
    return (result);
 
327
}
 
328
 
 
329
/* tls_pkey_fprint - extract public key fingerprint from certificate */
 
330
 
 
331
char   *tls_pkey_fprint(X509 *peercert, const char *mdalg)
 
332
{
 
333
    if (var_tls_bc_pkey_fprint) {
 
334
        const char *myname = "tls_pkey_fprint";
 
335
        ASN1_BIT_STRING *key;
 
336
        char   *result;
 
337
 
 
338
        key = X509_get0_pubkey_bitstr(peercert);
 
339
        if (key == 0)
 
340
            msg_fatal("%s: error extracting legacy public-key fingerprint: %m",
 
341
                      myname);
 
342
 
 
343
        result = tls_data_fprint((char *) key->data, key->length, mdalg);
 
344
        return (result);
 
345
    } else {
 
346
        int     len;
 
347
        char   *buf;
 
348
        char   *buf2;
 
349
        char   *result;
 
350
 
 
351
        len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(peercert), NULL);
 
352
        buf2 = buf = mymalloc(len);
 
353
        i2d_X509_PUBKEY(X509_get_X509_PUBKEY(peercert), (unsigned char **) &buf2);
 
354
        if (buf2 - buf != len)
 
355
            msg_panic("i2d_X509_PUBKEY invalid result length");
 
356
 
 
357
        result = tls_data_fprint(buf, len, mdalg);
 
358
        myfree(buf);
 
359
        return (result);
 
360
    }
 
361
}
 
362
 
 
363
#endif