Coverage Report

Created: 2023-03-26 07:11

/src/ntp-dev/libntp/a_md5encrypt.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *  digest support for NTP, MD5 and with OpenSSL more
3
 */
4
#ifdef HAVE_CONFIG_H
5
#include <config.h>
6
#endif
7
8
#include "ntp_fp.h"
9
#include "ntp_string.h"
10
#include "ntp_stdlib.h"
11
#include "ntp.h"
12
#include "ntp_md5.h"  /* provides OpenSSL digest API */
13
#include "isc/string.h"
14
15
typedef struct {
16
  const void *  buf;
17
  size_t    len;
18
} robuffT;
19
20
typedef struct {
21
  void *    buf;
22
  size_t    len;
23
} rwbuffT;
24
25
#if defined(OPENSSL) && defined(ENABLE_CMAC)
26
static size_t
27
cmac_ctx_size(
28
  CMAC_CTX *  ctx)
29
{
30
  size_t mlen = 0;
31
32
  if (ctx) {
33
    EVP_CIPHER_CTX *  cctx;
34
    if (NULL != (cctx = CMAC_CTX_get0_cipher_ctx (ctx)))
35
      mlen = EVP_CIPHER_CTX_block_size(cctx);
36
  }
37
  return mlen;
38
}
39
#endif /*OPENSSL && ENABLE_CMAC*/
40
41
static size_t
42
make_mac(
43
  const rwbuffT * digest,
44
  int   ktype,
45
  const robuffT * key,
46
  const robuffT * msg)
47
0
{
48
  /*
49
   * Compute digest of key concatenated with packet. Note: the
50
   * key type and digest type have been verified when the key
51
   * was created.
52
   */
53
0
  size_t  retlen = 0;
54
  
55
#ifdef OPENSSL
56
  
57
  INIT_SSL();
58
59
  /* Check if CMAC key type specific code required */
60
#   ifdef ENABLE_CMAC
61
  if (ktype == NID_cmac) {
62
    CMAC_CTX *  ctx    = NULL;
63
    void const *  keyptr = key->buf;
64
    u_char    keybuf[AES_128_KEY_SIZE];
65
66
    /* adjust key size (zero padded buffer) if necessary */
67
    if (AES_128_KEY_SIZE > key->len) {
68
      memcpy(keybuf, keyptr, key->len);
69
      memset((keybuf + key->len), 0,
70
             (AES_128_KEY_SIZE - key->len));
71
      keyptr = keybuf;
72
    }
73
    
74
    if (NULL == (ctx = CMAC_CTX_new())) {
75
      msyslog(LOG_ERR, "MAC encrypt: CMAC %s CTX new failed.", CMAC);
76
      goto cmac_fail;
77
    }
78
    if (!CMAC_Init(ctx, keyptr, AES_128_KEY_SIZE, EVP_aes_128_cbc(), NULL)) {
79
      msyslog(LOG_ERR, "MAC encrypt: CMAC %s Init failed.",    CMAC);
80
      goto cmac_fail;
81
    }
82
    if (cmac_ctx_size(ctx) > digest->len) {
83
      msyslog(LOG_ERR, "MAC encrypt: CMAC %s buf too small.",  CMAC);
84
      goto cmac_fail;
85
    }
86
    if (!CMAC_Update(ctx, msg->buf, msg->len)) {
87
      msyslog(LOG_ERR, "MAC encrypt: CMAC %s Update failed.",  CMAC);
88
      goto cmac_fail;
89
    }
90
    if (!CMAC_Final(ctx, digest->buf, &retlen)) {
91
      msyslog(LOG_ERR, "MAC encrypt: CMAC %s Final failed.",   CMAC);
92
      retlen = 0;
93
    }
94
    cmac_fail:
95
    if (ctx)
96
      CMAC_CTX_cleanup(ctx);
97
  }
98
  else
99
#   endif /*ENABLE_CMAC*/
100
  { /* generic MAC handling */
101
    EVP_MD_CTX *  ctx   = EVP_MD_CTX_new();
102
    u_int   uilen = 0;
103
    
104
    if ( ! ctx) {
105
      msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest CTX new failed.",
106
        OBJ_nid2sn(ktype));
107
      goto mac_fail;
108
    }
109
    
110
           #ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
111
    /* make sure MD5 is allowd */
112
    EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
113
           #endif
114
    /* [Bug 3457] DON'T use plain EVP_DigestInit! It would
115
     * kill the flags! */
116
    if (!EVP_DigestInit_ex(ctx, EVP_get_digestbynid(ktype), NULL)) {
117
      msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Init failed.",
118
        OBJ_nid2sn(ktype));
119
      goto mac_fail;
120
    }
121
    if ((size_t)EVP_MD_CTX_size(ctx) > digest->len) {
122
      msyslog(LOG_ERR, "MAC encrypt: MAC %s buf too small.",
123
        OBJ_nid2sn(ktype));
124
      goto mac_fail;
125
    }
126
    if (!EVP_DigestUpdate(ctx, key->buf, (u_int)key->len)) {
127
      msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update key failed.",
128
        OBJ_nid2sn(ktype));
129
      goto mac_fail;
130
    }
131
    if (!EVP_DigestUpdate(ctx, msg->buf, (u_int)msg->len)) {
132
      msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update data failed.",
133
        OBJ_nid2sn(ktype));
134
      goto mac_fail;
135
    }
136
    if (!EVP_DigestFinal(ctx, digest->buf, &uilen)) {
137
      msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Final failed.",
138
        OBJ_nid2sn(ktype));
139
      uilen = 0;
140
    }
141
    mac_fail:
142
    retlen = (size_t)uilen;
143
    
144
    if (ctx)
145
      EVP_MD_CTX_free(ctx);
146
  }
147
148
#else /* !OPENSSL follows */
149
  
150
0
  if (ktype == NID_md5)
151
0
  {
152
0
    EVP_MD_CTX *  ctx   = EVP_MD_CTX_new();
153
0
    u_int   uilen = 0;
154
155
0
    if (digest->len < 16) {
156
0
      msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 buf too small.");
157
0
    }
158
0
    else if ( ! ctx) {
159
0
      msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 Digest CTX new failed.");
160
0
    }
161
0
    else {
162
0
      EVP_DigestInit(ctx, EVP_get_digestbynid(ktype));
163
0
      EVP_DigestUpdate(ctx, key->buf, key->len);
164
0
      EVP_DigestUpdate(ctx, msg->buf, msg->len);
165
0
      EVP_DigestFinal(ctx, digest->buf, &uilen);
166
0
    }
167
0
    if (ctx)
168
0
      EVP_MD_CTX_free(ctx);
169
0
    retlen = (size_t)uilen;
170
0
  }
171
0
  else
172
0
  {
173
0
    msyslog(LOG_ERR, "MAC encrypt: invalid key type %d"  , ktype);
174
0
  }
175
  
176
0
#endif /* !OPENSSL */
177
178
0
  return retlen;
179
0
}
180
181
182
/*
183
 * MD5authencrypt - generate message digest
184
 *
185
 * Returns length of MAC including key ID and digest.
186
 */
187
size_t
188
MD5authencrypt(
189
  int   type, /* hash algorithm */
190
  const u_char *  key,  /* key pointer */
191
  size_t    klen, /* key length */
192
  u_int32 * pkt,  /* packet pointer */
193
  size_t    length  /* packet length */
194
  )
195
0
{
196
0
  u_char  digest[EVP_MAX_MD_SIZE];
197
0
  rwbuffT digb = { digest, sizeof(digest) };
198
0
  robuffT keyb = { key, klen };
199
0
  robuffT msgb = { pkt, length }; 
200
0
  size_t  dlen = 0;
201
202
0
  dlen = make_mac(&digb, type, &keyb, &msgb);
203
  /* If the MAC is longer than the MAX then truncate it. */
204
0
  if (dlen > MAX_MDG_LEN)
205
0
    dlen = MAX_MDG_LEN;
206
0
  memcpy((u_char *)pkt + length + KEY_MAC_LEN, digest, dlen);
207
0
  return (dlen + KEY_MAC_LEN);
208
0
}
209
210
211
/*
212
 * MD5authdecrypt - verify MD5 message authenticator
213
 *
214
 * Returns one if digest valid, zero if invalid.
215
 */
216
int
217
MD5authdecrypt(
218
  int   type, /* hash algorithm */
219
  const u_char *  key,  /* key pointer */
220
  size_t    klen, /* key length */
221
  u_int32 * pkt,  /* packet pointer */
222
  size_t    length, /* packet length */
223
  size_t    size  /* MAC size */
224
  )
225
0
{
226
0
  u_char  digest[EVP_MAX_MD_SIZE];
227
0
  rwbuffT digb = { digest, sizeof(digest) };
228
0
  robuffT keyb = { key, klen };
229
0
  robuffT msgb = { pkt, length }; 
230
0
  size_t  dlen = 0;
231
232
0
  dlen = make_mac(&digb, type, &keyb, &msgb);
233
  
234
  /* If the MAC is longer than the MAX then truncate it. */
235
0
  if (dlen > MAX_MDG_LEN)
236
0
    dlen = MAX_MDG_LEN;
237
0
  if (size != (size_t)dlen + KEY_MAC_LEN) {
238
0
    msyslog(LOG_ERR,
239
0
        "MAC decrypt: MAC length error");
240
0
    return (0);
241
0
  }
242
0
  return !isc_tsmemcmp(digest,
243
0
     (u_char *)pkt + length + KEY_MAC_LEN, dlen);
244
0
}
245
246
/*
247
 * Calculate the reference id from the address. If it is an IPv4
248
 * address, use it as is. If it is an IPv6 address, do a md5 on
249
 * it and use the bottom 4 bytes.
250
 * The result is in network byte order.
251
 */
252
u_int32
253
addr2refid(sockaddr_u *addr)
254
4
{
255
4
  u_char    digest[EVP_MAX_MD_SIZE];
256
4
  u_int32   addr_refid;
257
4
  EVP_MD_CTX  *ctx;
258
4
  u_int   len;
259
260
4
  if (IS_IPV4(addr))
261
3
    return (NSRCADR(addr));
262
263
1
  INIT_SSL();
264
265
1
  ctx = EVP_MD_CTX_new();
266
#   ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
267
  /* MD5 is not used as a crypto hash here. */
268
  EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
269
#   endif
270
  /* [Bug 3457] DON'T use plain EVP_DigestInit! It would kill the
271
   * flags! */
272
1
  if (!EVP_DigestInit_ex(ctx, EVP_md5(), NULL)) {
273
0
    msyslog(LOG_ERR,
274
0
        "MD5 init failed");
275
0
    EVP_MD_CTX_free(ctx);  /* pedantic... but safe */
276
0
    exit(1);
277
0
  }
278
279
1
  EVP_DigestUpdate(ctx, (u_char *)PSOCK_ADDR6(addr),
280
1
      sizeof(struct in6_addr));
281
1
  EVP_DigestFinal(ctx, digest, &len);
282
1
  EVP_MD_CTX_free(ctx);
283
1
  memcpy(&addr_refid, digest, sizeof(addr_refid));
284
1
  return (addr_refid);
285
1
}