Coverage Report

Created: 2024-02-29 06:05

/src/strongswan/src/libstrongswan/plugins/curve25519/curve25519_public_key.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2018 Tobias Brunner
3
 * Copyright (C) 2016 Andreas Steffen
4
 *
5
 * Copyright (C) secunet Security Networks AG
6
 *
7
 * This program is free software; you can redistribute it and/or modify it
8
 * under the terms of the GNU General Public License as published by the
9
 * Free Software Foundation; either version 2 of the License, or (at your
10
 * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
11
 *
12
 * This program is distributed in the hope that it will be useful, but
13
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15
 * for more details.
16
 */
17
18
#include "curve25519_public_key.h"
19
#include "ref10/ref10.h"
20
21
#include <asn1/asn1.h>
22
#include <asn1/asn1_parser.h>
23
#include <asn1/oid.h>
24
25
typedef struct private_curve25519_public_key_t private_curve25519_public_key_t;
26
27
/**
28
 * Private data structure with signing context.
29
 */
30
struct private_curve25519_public_key_t {
31
  /**
32
   * Public interface for this signer.
33
   */
34
  curve25519_public_key_t public;
35
36
  /**
37
   * Ed25519 public key
38
   */
39
  chunk_t pubkey;
40
41
  /**
42
   * Reference counter
43
   */
44
  refcount_t ref;
45
};
46
47
METHOD(public_key_t, get_type, key_type_t,
48
  private_curve25519_public_key_t *this)
49
0
{
50
0
  return KEY_ED25519;
51
0
}
52
53
/* L = 2^252+27742317777372353535851937790883648493 in little-endian form */
54
static chunk_t curve25519_order = chunk_from_chars(
55
                0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
56
                0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
57
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
58
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10);
59
60
METHOD(public_key_t, verify, bool,
61
  private_curve25519_public_key_t *this, signature_scheme_t scheme,
62
  void *params, chunk_t data, chunk_t signature)
63
0
{
64
0
  hasher_t *hasher;
65
0
  uint8_t d = 0, k[HASH_SIZE_SHA512], r[32], *sig;
66
0
  int i;
67
0
  ge_p3 A;
68
0
  ge_p2 R;
69
70
0
  if (scheme != SIGN_ED25519)
71
0
  {
72
0
    DBG1(DBG_LIB, "signature scheme %N not supported by Ed25519",
73
0
       signature_scheme_names, scheme);
74
0
    return FALSE;
75
0
  }
76
77
0
  if (signature.len != 64)
78
0
  {
79
0
    DBG1(DBG_LIB, "size of Ed25519 signature is not 64 bytes");
80
0
    return FALSE;
81
0
  }
82
0
  sig = signature.ptr;
83
84
0
  if (sig[63] & 0xe0)
85
0
  {
86
0
    DBG1(DBG_LIB, "the three most significant bits of Ed25519 signature "
87
0
       "are not zero");
88
0
    return FALSE;
89
0
  }
90
91
0
  if (ge_frombytes_negate_vartime(&A, this->pubkey.ptr) != 0)
92
0
  {
93
0
    return FALSE;
94
0
  }
95
96
  /* check for all-zeroes public key */
97
0
  for (i = 0; i < 32; i++)
98
0
  {
99
0
    d |= this->pubkey.ptr[i];
100
0
  }
101
0
  if (!d)
102
0
  {
103
0
    return FALSE;
104
0
  }
105
  /* make sure 0 <= s < L, as per RFC 8032, section 5.1.7 to prevent signature
106
   * malleability.  Due to the three-bit check above (forces s < 2^253) there
107
   * is not that much room, but adding L once works with most signatures */
108
0
  for (i = 31; ; i--)
109
0
  {
110
0
    if (sig[i+32] < curve25519_order.ptr[i])
111
0
    {
112
0
      break;
113
0
    }
114
0
    else if (sig[i+32] > curve25519_order.ptr[i] || i == 0)
115
0
    {
116
0
      return FALSE;
117
0
    }
118
0
  }
119
120
0
  hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA512);
121
0
  if (!hasher)
122
0
  {
123
0
    return FALSE;
124
0
  }
125
0
  if (!hasher->get_hash(hasher, chunk_create(sig, 32), NULL) ||
126
0
    !hasher->get_hash(hasher, this->pubkey, NULL) ||
127
0
    !hasher->get_hash(hasher, data, k))
128
0
  {
129
0
    hasher->destroy(hasher);
130
0
    return FALSE;
131
0
  }
132
0
  hasher->destroy(hasher);
133
134
0
  sc_reduce(k);
135
0
  ge_double_scalarmult_vartime(&R, k, &A, sig + 32);
136
0
  ge_tobytes(r, &R);
137
138
0
  return memeq_const(sig, r, 32);
139
0
}
140
141
METHOD(public_key_t, encrypt_, bool,
142
  private_curve25519_public_key_t *this, encryption_scheme_t scheme,
143
  void *params, chunk_t plain, chunk_t *crypto)
144
0
{
145
0
  DBG1(DBG_LIB, "encryption scheme %N not supported", encryption_scheme_names,
146
0
     scheme);
147
0
  return FALSE;
148
0
}
149
150
METHOD(public_key_t, get_keysize, int,
151
  private_curve25519_public_key_t *this)
152
0
{
153
0
  return 8 * ED25519_KEY_LEN;
154
0
}
155
156
METHOD(public_key_t, get_encoding, bool,
157
  private_curve25519_public_key_t *this, cred_encoding_type_t type,
158
  chunk_t *encoding)
159
0
{
160
0
  bool success = TRUE;
161
162
0
  *encoding = curve25519_public_key_info_encode(this->pubkey);
163
164
0
  if (type != PUBKEY_SPKI_ASN1_DER)
165
0
  {
166
0
    chunk_t asn1_encoding = *encoding;
167
168
0
    success = lib->encoding->encode(lib->encoding, type,
169
0
            NULL, encoding, CRED_PART_EDDSA_PUB_ASN1_DER,
170
0
            asn1_encoding, CRED_PART_END);
171
0
    chunk_clear(&asn1_encoding);
172
0
  }
173
0
  return success;
174
0
}
175
176
METHOD(public_key_t, get_fingerprint, bool,
177
  private_curve25519_public_key_t *this, cred_encoding_type_t type,
178
  chunk_t *fp)
179
0
{
180
0
  bool success;
181
182
0
  if (lib->encoding->get_cache(lib->encoding, type, this, fp))
183
0
  {
184
0
    return TRUE;
185
0
  }
186
0
  success = curve25519_public_key_fingerprint(this->pubkey, type, fp);
187
0
  if (success)
188
0
  {
189
0
    lib->encoding->cache(lib->encoding, type, this, fp);
190
0
  }
191
0
  return success;
192
0
}
193
194
METHOD(public_key_t, get_ref, public_key_t*,
195
  private_curve25519_public_key_t *this)
196
0
{
197
0
  ref_get(&this->ref);
198
0
  return &this->public.key;
199
0
}
200
201
METHOD(public_key_t, destroy, void,
202
  private_curve25519_public_key_t *this)
203
0
{
204
0
  if (ref_put(&this->ref))
205
0
  {
206
0
    lib->encoding->clear_cache(lib->encoding, this);
207
0
    free(this->pubkey.ptr);
208
0
    free(this);
209
0
  }
210
0
}
211
212
/**
213
 * ASN.1 definition of an Ed25519 public key
214
 */
215
static const asn1Object_t pubkeyObjects[] = {
216
  { 0, "subjectPublicKeyInfo",ASN1_SEQUENCE,    ASN1_NONE }, /*  0 */
217
  { 1,   "algorithm",     ASN1_EOC,     ASN1_RAW  }, /*  1 */
218
  { 1,   "subjectPublicKey",  ASN1_BIT_STRING,  ASN1_BODY }, /*  2 */
219
  { 0, "exit",        ASN1_EOC,     ASN1_EXIT }
220
};
221
222
0
#define ED25519_SUBJECT_PUBLIC_KEY_ALGORITHM  1
223
0
#define ED25519_SUBJECT_PUBLIC_KEY        2
224
225
/**
226
 * Parse the ASN.1-encoded subjectPublicKeyInfo
227
 */
228
static bool parse_public_key_info(private_curve25519_public_key_t *this,
229
                  chunk_t blob)
230
0
{
231
0
  asn1_parser_t *parser;
232
0
  chunk_t object;
233
0
  bool success = FALSE;
234
0
  int objectID, oid;
235
236
0
  parser = asn1_parser_create(pubkeyObjects, blob);
237
238
0
  while (parser->iterate(parser, &objectID, &object))
239
0
  {
240
0
    switch (objectID)
241
0
    {
242
0
      case ED25519_SUBJECT_PUBLIC_KEY_ALGORITHM:
243
0
      {
244
0
        oid = asn1_parse_algorithmIdentifier(object,
245
0
                    parser->get_level(parser) + 1, NULL);
246
0
        if (oid != OID_ED25519)
247
0
        {
248
0
          goto end;
249
0
        }
250
0
        break;
251
0
      }
252
0
      case ED25519_SUBJECT_PUBLIC_KEY:
253
0
      {
254
        /* encoded as an ASN1 BIT STRING */
255
0
        if (object.len != 1 + ED25519_KEY_LEN)
256
0
        {
257
0
          goto end;
258
0
        }
259
0
        this->pubkey = chunk_clone(chunk_skip(object, 1));
260
0
        break;
261
0
      }
262
0
    }
263
0
  }
264
0
  success = parser->success(parser);
265
266
0
end:
267
0
  parser->destroy(parser);
268
0
  return success;
269
0
}
270
271
/**
272
 * See header.
273
 */
274
curve25519_public_key_t *curve25519_public_key_load(key_type_t type,
275
                          va_list args)
276
0
{
277
0
  private_curve25519_public_key_t *this;
278
0
  chunk_t asn1 = chunk_empty, blob = chunk_empty;
279
280
0
  while (TRUE)
281
0
  {
282
0
    switch (va_arg(args, builder_part_t))
283
0
    {
284
0
      case BUILD_BLOB_ASN1_DER:
285
0
        asn1 = va_arg(args, chunk_t);
286
0
        continue;
287
0
      case BUILD_EDDSA_PUB:
288
0
        blob = va_arg(args, chunk_t);
289
0
        continue;
290
0
      case BUILD_END:
291
0
        break;
292
0
      default:
293
0
        return NULL;
294
0
    }
295
0
    break;
296
0
  }
297
298
0
  INIT(this,
299
0
    .public = {
300
0
      .key = {
301
0
        .get_type = _get_type,
302
0
        .verify = _verify,
303
0
        .encrypt = _encrypt_,
304
0
        .equals = public_key_equals,
305
0
        .get_keysize = _get_keysize,
306
0
        .get_fingerprint = _get_fingerprint,
307
0
        .has_fingerprint = public_key_has_fingerprint,
308
0
        .get_encoding = _get_encoding,
309
0
        .get_ref = _get_ref,
310
0
        .destroy = _destroy,
311
0
      },
312
0
    },
313
0
    .ref = 1,
314
0
  );
315
316
0
  if (blob.len == ED25519_KEY_LEN)
317
0
  {
318
0
    this->pubkey = chunk_clone(blob);
319
0
  }
320
0
  else if (!asn1.len || !parse_public_key_info(this, asn1))
321
0
  {
322
0
    destroy(this);
323
0
    return NULL;
324
0
  }
325
0
  return &this->public;
326
0
}
327
328
/**
329
 * See header.
330
 */
331
chunk_t curve25519_public_key_info_encode(chunk_t pubkey)
332
0
{
333
0
  return asn1_wrap(ASN1_SEQUENCE, "mm",
334
0
          asn1_wrap(ASN1_SEQUENCE, "m",
335
0
            asn1_build_known_oid(OID_ED25519)),
336
0
          asn1_bitstring("c", pubkey));
337
0
}
338
339
/**
340
 * See header.
341
 */
342
bool curve25519_public_key_fingerprint(chunk_t pubkey,
343
                     cred_encoding_type_t type, chunk_t *fp)
344
0
{
345
0
  hasher_t *hasher;
346
0
  chunk_t key;
347
348
0
  switch (type)
349
0
  {
350
0
    case KEYID_PUBKEY_SHA1:
351
0
      key = chunk_clone(pubkey);
352
0
      break;
353
0
    case KEYID_PUBKEY_INFO_SHA1:
354
0
      key = curve25519_public_key_info_encode(pubkey);
355
0
      break;
356
0
    default:
357
0
      return FALSE;
358
0
  }
359
360
0
  hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
361
0
  if (!hasher || !hasher->allocate_hash(hasher, key, fp))
362
0
  {
363
0
    DBG1(DBG_LIB, "SHA1 hash algorithm not supported, "
364
0
       "fingerprinting failed");
365
0
    DESTROY_IF(hasher);
366
0
    free(key.ptr);
367
0
    return FALSE;
368
0
  }
369
0
  hasher->destroy(hasher);
370
0
  free(key.ptr);
371
0
  return TRUE;
372
0
}