pq_crypto 0.5.3 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -15,6 +15,9 @@
15
15
  #include <openssl/crypto.h>
16
16
  #include <openssl/evp.h>
17
17
  #include <openssl/rand.h>
18
+ #include <openssl/x509.h>
19
+ #include <openssl/pkcs12.h>
20
+ #include <openssl/objects.h>
18
21
 
19
22
  #if OPENSSL_VERSION_NUMBER < 0x30000000L
20
23
  #error "OpenSSL 3.0 or later is required for pq_crypto"
@@ -73,7 +76,8 @@ cleanup:
73
76
  return ret;
74
77
  }
75
78
 
76
- static int x25519_shared_secret_with_pkey(uint8_t *shared, const uint8_t *their_pk, EVP_PKEY *pkey) {
79
+ static int x25519_shared_secret_with_pkey(uint8_t *shared, const uint8_t *their_pk,
80
+ EVP_PKEY *pkey) {
77
81
  EVP_PKEY_CTX *ctx = NULL;
78
82
  EVP_PKEY *peer_key = NULL;
79
83
  size_t shared_len = X25519_SHAREDSECRETBYTES;
@@ -131,7 +135,7 @@ static int x25519_shared_secret(uint8_t *shared, const uint8_t *their_pk, const
131
135
  }
132
136
 
133
137
  static int x25519_ephemeral_keypair_and_shared_secret(uint8_t *ephemeral_pk, uint8_t *shared,
134
- const uint8_t *their_pk) {
138
+ const uint8_t *their_pk) {
135
139
  EVP_PKEY_CTX *keygen_ctx = NULL;
136
140
  EVP_PKEY *ephemeral_pkey = NULL;
137
141
  size_t pklen = X25519_PUBLICKEYBYTES;
@@ -173,8 +177,8 @@ static int xwing_combiner(uint8_t shared_secret[HYBRID_SHAREDSECRETBYTES],
173
177
  const uint8_t ss_X[X25519_SHAREDSECRETBYTES],
174
178
  const uint8_t ct_X[X25519_PUBLICKEYBYTES],
175
179
  const uint8_t pk_X[X25519_PUBLICKEYBYTES]) {
176
- uint8_t input[MLKEM_SHAREDSECRETBYTES + X25519_SHAREDSECRETBYTES +
177
- X25519_PUBLICKEYBYTES + X25519_PUBLICKEYBYTES + sizeof(XWING_LABEL)];
180
+ uint8_t input[MLKEM_SHAREDSECRETBYTES + X25519_SHAREDSECRETBYTES + X25519_PUBLICKEYBYTES +
181
+ X25519_PUBLICKEYBYTES + sizeof(XWING_LABEL)];
178
182
  uint8_t *cur = input;
179
183
 
180
184
  if (!shared_secret || !ss_M || !ss_X || !ct_X || !pk_X) {
@@ -232,36 +236,35 @@ cleanup:
232
236
  return ret;
233
237
  }
234
238
 
235
- #define PQ_MLKEM_VARIANTS(X) \
236
- X(mlkem, pqcr_mlkem768) \
237
- X(mlkem512, pqcr_mlkem512) \
239
+ #define PQ_MLKEM_VARIANTS(X) \
240
+ X(mlkem, pqcr_mlkem768) \
241
+ X(mlkem512, pqcr_mlkem512) \
238
242
  X(mlkem1024, pqcr_mlkem1024)
239
243
 
240
- #define PQ_DEFINE_MLKEM_SHIMS(prefix, native) \
241
- int pq_##prefix##_keypair(uint8_t *pk, uint8_t *sk) { \
242
- if (!pk || !sk) { \
243
- return PQ_ERROR_BUFFER; \
244
- } \
245
- return native##_keypair(pk, sk) == 0 ? PQ_SUCCESS : PQ_ERROR_KEYPAIR; \
246
- } \
247
- int pq_##prefix##_keypair_from_seed(uint8_t *pk, uint8_t *sk, const uint8_t *seed64) {\
248
- if (!pk || !sk || !seed64) { \
249
- return PQ_ERROR_BUFFER; \
250
- } \
251
- return native##_keypair_derand(pk, sk, seed64) == 0 ? PQ_SUCCESS \
252
- : PQ_ERROR_KEYPAIR; \
253
- } \
254
- int pq_##prefix##_encapsulate(uint8_t *ct, uint8_t *ss, const uint8_t *pk) { \
255
- if (!ct || !ss || !pk) { \
256
- return PQ_ERROR_BUFFER; \
257
- } \
258
- return native##_enc(ct, ss, pk) == 0 ? PQ_SUCCESS : PQ_ERROR_ENCAPSULATE; \
259
- } \
260
- int pq_##prefix##_decapsulate(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) { \
261
- if (!ss || !ct || !sk) { \
262
- return PQ_ERROR_BUFFER; \
263
- } \
264
- return native##_dec(ss, ct, sk) == 0 ? PQ_SUCCESS : PQ_ERROR_DECAPSULATE; \
244
+ #define PQ_DEFINE_MLKEM_SHIMS(prefix, native) \
245
+ int pq_##prefix##_keypair(uint8_t *pk, uint8_t *sk) { \
246
+ if (!pk || !sk) { \
247
+ return PQ_ERROR_BUFFER; \
248
+ } \
249
+ return native##_keypair(pk, sk) == 0 ? PQ_SUCCESS : PQ_ERROR_KEYPAIR; \
250
+ } \
251
+ int pq_##prefix##_keypair_from_seed(uint8_t *pk, uint8_t *sk, const uint8_t *seed64) { \
252
+ if (!pk || !sk || !seed64) { \
253
+ return PQ_ERROR_BUFFER; \
254
+ } \
255
+ return native##_keypair_derand(pk, sk, seed64) == 0 ? PQ_SUCCESS : PQ_ERROR_KEYPAIR; \
256
+ } \
257
+ int pq_##prefix##_encapsulate(uint8_t *ct, uint8_t *ss, const uint8_t *pk) { \
258
+ if (!ct || !ss || !pk) { \
259
+ return PQ_ERROR_BUFFER; \
260
+ } \
261
+ return native##_enc(ct, ss, pk) == 0 ? PQ_SUCCESS : PQ_ERROR_ENCAPSULATE; \
262
+ } \
263
+ int pq_##prefix##_decapsulate(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) { \
264
+ if (!ss || !ct || !sk) { \
265
+ return PQ_ERROR_BUFFER; \
266
+ } \
267
+ return native##_dec(ss, ct, sk) == 0 ? PQ_SUCCESS : PQ_ERROR_DECAPSULATE; \
265
268
  }
266
269
 
267
270
  PQ_MLKEM_VARIANTS(PQ_DEFINE_MLKEM_SHIMS)
@@ -288,30 +291,29 @@ static int pq_testing_mlkem_encapsulate_from_seed_with(
288
291
  : PQ_ERROR_ENCAPSULATE;
289
292
  }
290
293
 
291
- #define PQ_DEFINE_MLKEM_TESTING_SHIMS(prefix, native) \
292
- int pq_testing_##prefix##_keypair_from_seed(uint8_t *public_key, uint8_t *secret_key, \
293
- const uint8_t *seed, size_t seed_len) { \
294
- return pq_testing_mlkem_keypair_from_seed_with(public_key, secret_key, seed, seed_len, \
295
- native##_keypair_derand); \
296
- } \
297
- int pq_testing_##prefix##_encapsulate_from_seed(uint8_t *ciphertext, uint8_t *shared_secret,\
298
- const uint8_t *public_key, \
299
- const uint8_t *seed, size_t seed_len) { \
300
- return pq_testing_mlkem_encapsulate_from_seed_with(ciphertext, shared_secret, public_key,\
301
- seed, seed_len, native##_enc_derand);\
294
+ #define PQ_DEFINE_MLKEM_TESTING_SHIMS(prefix, native) \
295
+ int pq_testing_##prefix##_keypair_from_seed(uint8_t *public_key, uint8_t *secret_key, \
296
+ const uint8_t *seed, size_t seed_len) { \
297
+ return pq_testing_mlkem_keypair_from_seed_with(public_key, secret_key, seed, seed_len, \
298
+ native##_keypair_derand); \
299
+ } \
300
+ int pq_testing_##prefix##_encapsulate_from_seed(uint8_t *ciphertext, uint8_t *shared_secret, \
301
+ const uint8_t *public_key, \
302
+ const uint8_t *seed, size_t seed_len) { \
303
+ return pq_testing_mlkem_encapsulate_from_seed_with(ciphertext, shared_secret, public_key, \
304
+ seed, seed_len, native##_enc_derand); \
302
305
  }
303
306
 
304
307
  PQ_MLKEM_VARIANTS(PQ_DEFINE_MLKEM_TESTING_SHIMS)
305
308
 
306
309
  #undef PQ_DEFINE_MLKEM_TESTING_SHIMS
307
310
 
308
- #define PQ_DEFINE_MLDSA_SIGN_KEYPAIR(prefix, native) \
309
- int pq_##prefix##_keypair(uint8_t *public_key, uint8_t *secret_key) { \
310
- if (!public_key || !secret_key) { \
311
- return PQ_ERROR_BUFFER; \
312
- } \
313
- return native##_keypair(public_key, secret_key) == 0 ? PQ_SUCCESS \
314
- : PQ_ERROR_KEYPAIR; \
311
+ #define PQ_DEFINE_MLDSA_SIGN_KEYPAIR(prefix, native) \
312
+ int pq_##prefix##_keypair(uint8_t *public_key, uint8_t *secret_key) { \
313
+ if (!public_key || !secret_key) { \
314
+ return PQ_ERROR_BUFFER; \
315
+ } \
316
+ return native##_keypair(public_key, secret_key) == 0 ? PQ_SUCCESS : PQ_ERROR_KEYPAIR; \
315
317
  }
316
318
 
317
319
  PQ_DEFINE_MLDSA_SIGN_KEYPAIR(sign, pqcr_mldsa65)
@@ -320,16 +322,18 @@ PQ_DEFINE_MLDSA_SIGN_KEYPAIR(mldsa87_sign, pqcr_mldsa87)
320
322
 
321
323
  #undef PQ_DEFINE_MLDSA_SIGN_KEYPAIR
322
324
 
323
- #define PQ_DEFINE_MLDSA_SIGN(name, native) \
324
- int pq_##name(uint8_t *signature, size_t *signature_len, const uint8_t *message, \
325
- size_t message_len, const uint8_t *secret_key) { \
326
- if (!signature || !signature_len || !secret_key || (message_len > 0 && !message)) {\
327
- return PQ_ERROR_BUFFER; \
328
- } \
329
- return native##_signature(signature, signature_len, message, message_len, NULL, 0,\
330
- secret_key) == 0 \
331
- ? PQ_SUCCESS \
332
- : PQ_ERROR_SIGN; \
325
+ #define PQ_DEFINE_MLDSA_SIGN(name, native) \
326
+ int pq_##name(uint8_t *signature, size_t *signature_len, const uint8_t *message, \
327
+ size_t message_len, const uint8_t *ctx, size_t ctx_len, \
328
+ const uint8_t *secret_key) { \
329
+ if (!signature || !signature_len || !secret_key || (message_len > 0 && !message) || \
330
+ (ctx_len > 0 && !ctx) || ctx_len > 255) { \
331
+ return PQ_ERROR_BUFFER; \
332
+ } \
333
+ return native##_signature(signature, signature_len, message, message_len, ctx, ctx_len, \
334
+ secret_key) == 0 \
335
+ ? PQ_SUCCESS \
336
+ : PQ_ERROR_SIGN; \
333
337
  }
334
338
 
335
339
  PQ_DEFINE_MLDSA_SIGN(sign, pqcr_mldsa65)
@@ -338,16 +342,18 @@ PQ_DEFINE_MLDSA_SIGN(mldsa87_sign, pqcr_mldsa87)
338
342
 
339
343
  #undef PQ_DEFINE_MLDSA_SIGN
340
344
 
341
- #define PQ_DEFINE_MLDSA_VERIFY(name, native) \
342
- int pq_##name(const uint8_t *signature, size_t signature_len, const uint8_t *message, \
343
- size_t message_len, const uint8_t *public_key) { \
344
- if (!signature || !public_key || (message_len > 0 && !message)) { \
345
- return PQ_ERROR_BUFFER; \
346
- } \
347
- return native##_verify(signature, signature_len, message, message_len, NULL, 0, \
348
- public_key) == 0 \
349
- ? PQ_SUCCESS \
350
- : PQ_ERROR_VERIFY; \
345
+ #define PQ_DEFINE_MLDSA_VERIFY(name, native) \
346
+ int pq_##name(const uint8_t *signature, size_t signature_len, const uint8_t *message, \
347
+ size_t message_len, const uint8_t *ctx, size_t ctx_len, \
348
+ const uint8_t *public_key) { \
349
+ if (!signature || !public_key || (message_len > 0 && !message) || (ctx_len > 0 && !ctx) || \
350
+ ctx_len > 255) { \
351
+ return PQ_ERROR_BUFFER; \
352
+ } \
353
+ return native##_verify(signature, signature_len, message, message_len, ctx, ctx_len, \
354
+ public_key) == 0 \
355
+ ? PQ_SUCCESS \
356
+ : PQ_ERROR_VERIFY; \
351
357
  }
352
358
 
353
359
  PQ_DEFINE_MLDSA_VERIFY(verify, pqcr_mldsa65)
@@ -440,30 +446,27 @@ int pq_testing_mldsa_sign_from_seed(uint8_t *signature, size_t *signature_len,
440
446
  const uint8_t *message, size_t message_len,
441
447
  const uint8_t *secret_key, const uint8_t *seed,
442
448
  size_t seed_len) {
443
- return pq_testing_mldsa_sign_from_seed_with(signature, signature_len, message, message_len,
444
- secret_key, seed, seed_len,
445
- pqcr_mldsa65_signature_internal,
446
- pqcr_mldsa65_prepare_domain_separation_prefix);
449
+ return pq_testing_mldsa_sign_from_seed_with(
450
+ signature, signature_len, message, message_len, secret_key, seed, seed_len,
451
+ pqcr_mldsa65_signature_internal, pqcr_mldsa65_prepare_domain_separation_prefix);
447
452
  }
448
453
 
449
454
  int pq_testing_mldsa44_sign_from_seed(uint8_t *signature, size_t *signature_len,
450
455
  const uint8_t *message, size_t message_len,
451
456
  const uint8_t *secret_key, const uint8_t *seed,
452
457
  size_t seed_len) {
453
- return pq_testing_mldsa_sign_from_seed_with(signature, signature_len, message, message_len,
454
- secret_key, seed, seed_len,
455
- pqcr_mldsa44_signature_internal,
456
- pqcr_mldsa44_prepare_domain_separation_prefix);
458
+ return pq_testing_mldsa_sign_from_seed_with(
459
+ signature, signature_len, message, message_len, secret_key, seed, seed_len,
460
+ pqcr_mldsa44_signature_internal, pqcr_mldsa44_prepare_domain_separation_prefix);
457
461
  }
458
462
 
459
463
  int pq_testing_mldsa87_sign_from_seed(uint8_t *signature, size_t *signature_len,
460
464
  const uint8_t *message, size_t message_len,
461
465
  const uint8_t *secret_key, const uint8_t *seed,
462
466
  size_t seed_len) {
463
- return pq_testing_mldsa_sign_from_seed_with(signature, signature_len, message, message_len,
464
- secret_key, seed, seed_len,
465
- pqcr_mldsa87_signature_internal,
466
- pqcr_mldsa87_prepare_domain_separation_prefix);
467
+ return pq_testing_mldsa_sign_from_seed_with(
468
+ signature, signature_len, message, message_len, secret_key, seed, seed_len,
469
+ pqcr_mldsa87_signature_internal, pqcr_mldsa87_prepare_domain_separation_prefix);
467
470
  }
468
471
 
469
472
  int pq_hybrid_kem_keypair(uint8_t *public_key, uint8_t *secret_key) {
@@ -523,8 +526,7 @@ int pq_hybrid_kem_encapsulate(uint8_t *ciphertext, uint8_t *shared_secret,
523
526
  goto cleanup;
524
527
  }
525
528
 
526
- ret = x25519_ephemeral_keypair_and_shared_secret(ct.x25519_ephemeral, x25519_ss,
527
- pk.x25519_pk);
529
+ ret = x25519_ephemeral_keypair_and_shared_secret(ct.x25519_ephemeral, x25519_ss, pk.x25519_pk);
528
530
  if (ret != PQ_SUCCESS) {
529
531
  ret = PQ_ERROR_ENCAPSULATE;
530
532
  goto cleanup;
@@ -1160,6 +1162,535 @@ int pq_secret_key_from_pqc_container_pem(char **algorithm_out, uint8_t **key_out
1160
1162
  return ret;
1161
1163
  }
1162
1164
 
1165
+ #define PQ_PKCS8_PRIVATE_KEY_PEM_LABEL "PRIVATE KEY"
1166
+ #define PQ_PKCS8_ENCRYPTED_PRIVATE_KEY_PEM_LABEL "ENCRYPTED PRIVATE KEY"
1167
+
1168
+ static size_t pq_der_length_octets(size_t len) {
1169
+ size_t octets = 0;
1170
+ size_t v = len;
1171
+
1172
+ if (len < 0x80)
1173
+ return 1;
1174
+ do {
1175
+ octets++;
1176
+ v >>= 8;
1177
+ } while (v != 0);
1178
+ return 1 + octets;
1179
+ }
1180
+
1181
+ static int pq_der_write_length(uint8_t **cursor, size_t len) {
1182
+ uint8_t *p;
1183
+ size_t octets = 0;
1184
+ size_t v = len;
1185
+
1186
+ if (!cursor || !*cursor)
1187
+ return PQ_ERROR_BUFFER;
1188
+
1189
+ p = *cursor;
1190
+ if (len < 0x80) {
1191
+ *p++ = (uint8_t)len;
1192
+ *cursor = p;
1193
+ return PQ_SUCCESS;
1194
+ }
1195
+
1196
+ do {
1197
+ octets++;
1198
+ v >>= 8;
1199
+ } while (v != 0);
1200
+ if (octets > sizeof(size_t))
1201
+ return PQ_ERROR_BUFFER;
1202
+
1203
+ *p++ = (uint8_t)(0x80u | (uint8_t)octets);
1204
+ for (size_t i = 0; i < octets; ++i) {
1205
+ size_t shift = 8 * (octets - 1 - i);
1206
+ *p++ = (uint8_t)((len >> shift) & 0xffu);
1207
+ }
1208
+ *cursor = p;
1209
+ return PQ_SUCCESS;
1210
+ }
1211
+
1212
+ static int pq_der_read_length(const uint8_t *input, size_t input_len, size_t *offset,
1213
+ size_t *len_out) {
1214
+ uint8_t first;
1215
+ size_t len = 0;
1216
+ size_t length_octets;
1217
+
1218
+ if (!input || !offset || !len_out || *offset >= input_len)
1219
+ return PQ_ERROR_BUFFER;
1220
+
1221
+ first = input[(*offset)++];
1222
+ if (first < 0x80) {
1223
+ *len_out = (size_t)first;
1224
+ return PQ_SUCCESS;
1225
+ }
1226
+
1227
+ length_octets = (size_t)(first & 0x7fu);
1228
+ if (length_octets == 0 || length_octets > sizeof(size_t))
1229
+ return PQ_ERROR_BUFFER;
1230
+ if (input_len - *offset < length_octets)
1231
+ return PQ_ERROR_BUFFER;
1232
+ if (input[*offset] == 0)
1233
+ return PQ_ERROR_BUFFER;
1234
+
1235
+ for (size_t i = 0; i < length_octets; ++i) {
1236
+ if (len > (SIZE_MAX >> 8))
1237
+ return PQ_ERROR_BUFFER;
1238
+ len = (len << 8) | (size_t)input[*offset + i];
1239
+ }
1240
+ if (len < 0x80)
1241
+ return PQ_ERROR_BUFFER;
1242
+
1243
+ *offset += length_octets;
1244
+ *len_out = len;
1245
+ return PQ_SUCCESS;
1246
+ }
1247
+
1248
+ static int pq_der_expect_tlv(const uint8_t *input, size_t input_len, size_t *offset,
1249
+ uint8_t expected_tag, size_t *value_offset_out,
1250
+ size_t *value_len_out) {
1251
+ size_t value_len;
1252
+ size_t value_offset;
1253
+
1254
+ if (!input || !offset || !value_offset_out || !value_len_out || *offset >= input_len)
1255
+ return PQ_ERROR_BUFFER;
1256
+ if (input[(*offset)++] != expected_tag)
1257
+ return PQ_ERROR_BUFFER;
1258
+ if (pq_der_read_length(input, input_len, offset, &value_len) != PQ_SUCCESS)
1259
+ return PQ_ERROR_BUFFER;
1260
+ value_offset = *offset;
1261
+ if (input_len - value_offset < value_len)
1262
+ return PQ_ERROR_BUFFER;
1263
+ *offset = value_offset + value_len;
1264
+ *value_offset_out = value_offset;
1265
+ *value_len_out = value_len;
1266
+ return PQ_SUCCESS;
1267
+ }
1268
+
1269
+ static int pq_oid_text_to_der(const char *oid_text, uint8_t **oid_der_out,
1270
+ size_t *oid_der_len_out) {
1271
+ ASN1_OBJECT *obj = NULL;
1272
+ uint8_t *der = NULL;
1273
+ unsigned char *cursor;
1274
+ int der_len;
1275
+ int ret = PQ_ERROR_OPENSSL;
1276
+
1277
+ if (!oid_text || !oid_der_out || !oid_der_len_out)
1278
+ return PQ_ERROR_BUFFER;
1279
+ *oid_der_out = NULL;
1280
+ *oid_der_len_out = 0;
1281
+
1282
+ obj = OBJ_txt2obj(oid_text, 1);
1283
+ if (!obj)
1284
+ goto cleanup;
1285
+ der_len = i2d_ASN1_OBJECT(obj, NULL);
1286
+ if (der_len <= 0)
1287
+ goto cleanup;
1288
+ der = malloc((size_t)der_len);
1289
+ if (!der) {
1290
+ ret = PQ_ERROR_NOMEM;
1291
+ goto cleanup;
1292
+ }
1293
+ cursor = der;
1294
+ if (i2d_ASN1_OBJECT(obj, &cursor) != der_len || (size_t)(cursor - der) != (size_t)der_len)
1295
+ goto cleanup;
1296
+
1297
+ *oid_der_out = der;
1298
+ *oid_der_len_out = (size_t)der_len;
1299
+ der = NULL;
1300
+ ret = PQ_SUCCESS;
1301
+
1302
+ cleanup:
1303
+ if (der) {
1304
+ pq_secure_wipe(der, (size_t)(der_len > 0 ? der_len : 0));
1305
+ free(der);
1306
+ }
1307
+ if (obj)
1308
+ ASN1_OBJECT_free(obj);
1309
+ return ret;
1310
+ }
1311
+
1312
+ static int pq_oid_der_to_text(const uint8_t *oid_der, size_t oid_der_len, char **oid_text_out) {
1313
+ ASN1_OBJECT *obj = NULL;
1314
+ const unsigned char *cursor;
1315
+ char tmp[128];
1316
+ int text_len;
1317
+ char *copy = NULL;
1318
+ int ret = PQ_ERROR_OPENSSL;
1319
+
1320
+ if (!oid_der || oid_der_len == 0 || oid_der_len > (size_t)LONG_MAX || !oid_text_out)
1321
+ return PQ_ERROR_BUFFER;
1322
+ *oid_text_out = NULL;
1323
+
1324
+ cursor = oid_der;
1325
+ obj = d2i_ASN1_OBJECT(NULL, &cursor, (long)oid_der_len);
1326
+ if (!obj || cursor != oid_der + oid_der_len)
1327
+ goto cleanup;
1328
+ text_len = OBJ_obj2txt(tmp, sizeof(tmp), obj, 1);
1329
+ if (text_len <= 0 || (size_t)text_len >= sizeof(tmp))
1330
+ goto cleanup;
1331
+ copy = malloc((size_t)text_len + 1);
1332
+ if (!copy) {
1333
+ ret = PQ_ERROR_NOMEM;
1334
+ goto cleanup;
1335
+ }
1336
+ memcpy(copy, tmp, (size_t)text_len + 1);
1337
+ *oid_text_out = copy;
1338
+ copy = NULL;
1339
+ ret = PQ_SUCCESS;
1340
+
1341
+ cleanup:
1342
+ if (copy)
1343
+ free(copy);
1344
+ if (obj)
1345
+ ASN1_OBJECT_free(obj);
1346
+ return ret;
1347
+ }
1348
+
1349
+ int pq_pkcs8_private_key_info_to_der(uint8_t **output, size_t *output_len, const char *oid_text,
1350
+ const uint8_t *private_key, size_t private_key_len) {
1351
+ uint8_t *oid_der = NULL;
1352
+ size_t oid_der_len = 0;
1353
+ size_t alg_body_len, alg_len, priv_len, inner_len, total_len;
1354
+ uint8_t *buf = NULL;
1355
+ uint8_t *cur;
1356
+ int ret;
1357
+
1358
+ if (!output || !output_len || !oid_text || !private_key)
1359
+ return PQ_ERROR_BUFFER;
1360
+ *output = NULL;
1361
+ *output_len = 0;
1362
+
1363
+ ret = pq_oid_text_to_der(oid_text, &oid_der, &oid_der_len);
1364
+ if (ret != PQ_SUCCESS)
1365
+ return ret;
1366
+
1367
+ alg_body_len = oid_der_len;
1368
+ alg_len = 1 + pq_der_length_octets(alg_body_len) + alg_body_len;
1369
+ priv_len = 1 + pq_der_length_octets(private_key_len) + private_key_len;
1370
+ if (pq_size_add(3, alg_len, &inner_len) != PQ_SUCCESS ||
1371
+ pq_size_add(inner_len, priv_len, &inner_len) != PQ_SUCCESS) {
1372
+ ret = PQ_ERROR_BUFFER;
1373
+ goto cleanup;
1374
+ }
1375
+ if (pq_size_add(1 + pq_der_length_octets(inner_len), inner_len, &total_len) != PQ_SUCCESS) {
1376
+ ret = PQ_ERROR_BUFFER;
1377
+ goto cleanup;
1378
+ }
1379
+
1380
+ buf = malloc(total_len);
1381
+ if (!buf) {
1382
+ ret = PQ_ERROR_NOMEM;
1383
+ goto cleanup;
1384
+ }
1385
+
1386
+ cur = buf;
1387
+ *cur++ = 0x30;
1388
+ ret = pq_der_write_length(&cur, inner_len);
1389
+ if (ret != PQ_SUCCESS)
1390
+ goto cleanup;
1391
+ *cur++ = 0x02;
1392
+ *cur++ = 0x01;
1393
+ *cur++ = 0x00;
1394
+ *cur++ = 0x30;
1395
+ ret = pq_der_write_length(&cur, alg_body_len);
1396
+ if (ret != PQ_SUCCESS)
1397
+ goto cleanup;
1398
+ memcpy(cur, oid_der, oid_der_len);
1399
+ cur += oid_der_len;
1400
+ *cur++ = 0x04;
1401
+ ret = pq_der_write_length(&cur, private_key_len);
1402
+ if (ret != PQ_SUCCESS)
1403
+ goto cleanup;
1404
+ memcpy(cur, private_key, private_key_len);
1405
+ cur += private_key_len;
1406
+ if ((size_t)(cur - buf) != total_len) {
1407
+ ret = PQ_ERROR_BUFFER;
1408
+ goto cleanup;
1409
+ }
1410
+
1411
+ *output = buf;
1412
+ *output_len = total_len;
1413
+ buf = NULL;
1414
+ ret = PQ_SUCCESS;
1415
+
1416
+ cleanup:
1417
+ if (buf) {
1418
+ pq_secure_wipe(buf, total_len);
1419
+ free(buf);
1420
+ }
1421
+ if (oid_der) {
1422
+ pq_secure_wipe(oid_der, oid_der_len);
1423
+ free(oid_der);
1424
+ }
1425
+ return ret;
1426
+ }
1427
+
1428
+ int pq_pkcs8_private_key_info_from_der(char **oid_text_out, uint8_t **private_key_out,
1429
+ size_t *private_key_len_out, const uint8_t *input,
1430
+ size_t input_len) {
1431
+ size_t offset = 0;
1432
+ size_t outer_off = 0, outer_len = 0, outer_end;
1433
+ size_t alg_off = 0, alg_len = 0, alg_end;
1434
+ size_t oid_off = 0, oid_len = 0;
1435
+ size_t priv_off = 0, priv_len = 0;
1436
+ uint8_t *private_key = NULL;
1437
+ char *oid_text = NULL;
1438
+ int ret;
1439
+
1440
+ if (!oid_text_out || !private_key_out || !private_key_len_out || !input)
1441
+ return PQ_ERROR_BUFFER;
1442
+ *oid_text_out = NULL;
1443
+ *private_key_out = NULL;
1444
+ *private_key_len_out = 0;
1445
+
1446
+ ret = pq_der_expect_tlv(input, input_len, &offset, 0x30, &outer_off, &outer_len);
1447
+ if (ret != PQ_SUCCESS)
1448
+ return ret;
1449
+ outer_end = outer_off + outer_len;
1450
+ if (offset != input_len || outer_end != input_len)
1451
+ return PQ_ERROR_BUFFER;
1452
+
1453
+ offset = outer_off;
1454
+ {
1455
+ size_t version_off = 0, version_len = 0;
1456
+ ret = pq_der_expect_tlv(input, outer_end, &offset, 0x02, &version_off, &version_len);
1457
+ if (ret != PQ_SUCCESS)
1458
+ return ret;
1459
+ if (version_len != 1 || input[version_off] != 0x00)
1460
+ return PQ_ERROR_BUFFER;
1461
+ }
1462
+
1463
+ ret = pq_der_expect_tlv(input, outer_end, &offset, 0x30, &alg_off, &alg_len);
1464
+ if (ret != PQ_SUCCESS)
1465
+ return ret;
1466
+ alg_end = alg_off + alg_len;
1467
+ {
1468
+ size_t alg_cursor = alg_off;
1469
+ size_t oid_tlv_start = alg_cursor;
1470
+ ret = pq_der_expect_tlv(input, alg_end, &alg_cursor, 0x06, &oid_off, &oid_len);
1471
+ if (ret != PQ_SUCCESS)
1472
+ return ret;
1473
+ if (alg_cursor != alg_end)
1474
+ return PQ_ERROR_BUFFER;
1475
+ ret = pq_oid_der_to_text(input + oid_tlv_start, alg_cursor - oid_tlv_start, &oid_text);
1476
+ }
1477
+ if (ret != PQ_SUCCESS)
1478
+ return ret;
1479
+
1480
+ ret = pq_der_expect_tlv(input, outer_end, &offset, 0x04, &priv_off, &priv_len);
1481
+ if (ret != PQ_SUCCESS)
1482
+ goto cleanup;
1483
+ if (offset != outer_end) {
1484
+ ret = PQ_ERROR_BUFFER;
1485
+ goto cleanup;
1486
+ }
1487
+ private_key = malloc(priv_len ? priv_len : 1);
1488
+ if (!private_key) {
1489
+ ret = PQ_ERROR_NOMEM;
1490
+ goto cleanup;
1491
+ }
1492
+ if (priv_len)
1493
+ memcpy(private_key, input + priv_off, priv_len);
1494
+
1495
+ *oid_text_out = oid_text;
1496
+ *private_key_out = private_key;
1497
+ *private_key_len_out = priv_len;
1498
+ oid_text = NULL;
1499
+ private_key = NULL;
1500
+ ret = PQ_SUCCESS;
1501
+
1502
+ cleanup:
1503
+ if (oid_text)
1504
+ free(oid_text);
1505
+ if (private_key) {
1506
+ pq_secure_wipe(private_key, priv_len);
1507
+ free(private_key);
1508
+ }
1509
+ return ret;
1510
+ }
1511
+
1512
+ int pq_pkcs8_encrypt_private_key_info_der(uint8_t **output, size_t *output_len,
1513
+ const uint8_t *plain_der, size_t plain_der_len,
1514
+ const char *passphrase, size_t passphrase_len,
1515
+ int iterations) {
1516
+ const unsigned char *cursor;
1517
+ PKCS8_PRIV_KEY_INFO *p8 = NULL;
1518
+ X509_SIG *encrypted = NULL;
1519
+ unsigned char salt[16];
1520
+ unsigned char *der = NULL;
1521
+ unsigned char *der_cursor;
1522
+ int der_len;
1523
+ int ret = PQ_ERROR_OPENSSL;
1524
+
1525
+ if (!output || !output_len || !plain_der || !passphrase || iterations <= 0 ||
1526
+ passphrase_len > (size_t)INT_MAX || plain_der_len > (size_t)LONG_MAX)
1527
+ return PQ_ERROR_BUFFER;
1528
+ *output = NULL;
1529
+ *output_len = 0;
1530
+
1531
+ cursor = plain_der;
1532
+ p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &cursor, (long)plain_der_len);
1533
+ if (!p8 || cursor != plain_der + plain_der_len)
1534
+ goto cleanup;
1535
+ if (RAND_bytes(salt, sizeof(salt)) != 1)
1536
+ goto cleanup;
1537
+
1538
+ encrypted = PKCS8_encrypt(-1, EVP_aes_256_cbc(), passphrase, (int)passphrase_len, salt,
1539
+ (int)sizeof(salt), iterations, p8);
1540
+ if (!encrypted)
1541
+ goto cleanup;
1542
+
1543
+ der_len = i2d_X509_SIG(encrypted, NULL);
1544
+ if (der_len <= 0) {
1545
+ ret = PQ_ERROR_OPENSSL;
1546
+ goto cleanup;
1547
+ }
1548
+ der = malloc((size_t)der_len);
1549
+ if (!der) {
1550
+ ret = PQ_ERROR_NOMEM;
1551
+ goto cleanup;
1552
+ }
1553
+ der_cursor = der;
1554
+ if (i2d_X509_SIG(encrypted, &der_cursor) != der_len ||
1555
+ (size_t)(der_cursor - der) != (size_t)der_len)
1556
+ goto cleanup;
1557
+
1558
+ *output = der;
1559
+ *output_len = (size_t)der_len;
1560
+ der = NULL;
1561
+ ret = PQ_SUCCESS;
1562
+
1563
+ cleanup:
1564
+ pq_secure_wipe(salt, sizeof(salt));
1565
+ if (der) {
1566
+ pq_secure_wipe(der, (size_t)(der_len > 0 ? der_len : 0));
1567
+ free(der);
1568
+ }
1569
+ if (encrypted)
1570
+ X509_SIG_free(encrypted);
1571
+ if (p8)
1572
+ PKCS8_PRIV_KEY_INFO_free(p8);
1573
+ return ret;
1574
+ }
1575
+
1576
+ int pq_pkcs8_decrypt_private_key_info_der(uint8_t **output, size_t *output_len,
1577
+ const uint8_t *encrypted_der, size_t encrypted_der_len,
1578
+ const char *passphrase, size_t passphrase_len) {
1579
+ const unsigned char *cursor;
1580
+ X509_SIG *encrypted = NULL;
1581
+ PKCS8_PRIV_KEY_INFO *p8 = NULL;
1582
+ unsigned char *der = NULL;
1583
+ unsigned char *der_cursor;
1584
+ int der_len;
1585
+ int ret = PQ_ERROR_OPENSSL;
1586
+
1587
+ if (!output || !output_len || !encrypted_der || !passphrase ||
1588
+ passphrase_len > (size_t)INT_MAX || encrypted_der_len > (size_t)LONG_MAX)
1589
+ return PQ_ERROR_BUFFER;
1590
+ *output = NULL;
1591
+ *output_len = 0;
1592
+
1593
+ cursor = encrypted_der;
1594
+ encrypted = d2i_X509_SIG(NULL, &cursor, (long)encrypted_der_len);
1595
+ if (!encrypted || cursor != encrypted_der + encrypted_der_len)
1596
+ goto cleanup;
1597
+ p8 = PKCS8_decrypt(encrypted, passphrase, (int)passphrase_len);
1598
+ if (!p8)
1599
+ goto cleanup;
1600
+
1601
+ der_len = i2d_PKCS8_PRIV_KEY_INFO(p8, NULL);
1602
+ if (der_len <= 0)
1603
+ goto cleanup;
1604
+ der = malloc((size_t)der_len);
1605
+ if (!der) {
1606
+ ret = PQ_ERROR_NOMEM;
1607
+ goto cleanup;
1608
+ }
1609
+ der_cursor = der;
1610
+ if (i2d_PKCS8_PRIV_KEY_INFO(p8, &der_cursor) != der_len ||
1611
+ (size_t)(der_cursor - der) != (size_t)der_len)
1612
+ goto cleanup;
1613
+
1614
+ *output = der;
1615
+ *output_len = (size_t)der_len;
1616
+ der = NULL;
1617
+ ret = PQ_SUCCESS;
1618
+
1619
+ cleanup:
1620
+ if (der) {
1621
+ pq_secure_wipe(der, (size_t)(der_len > 0 ? der_len : 0));
1622
+ free(der);
1623
+ }
1624
+ if (p8)
1625
+ PKCS8_PRIV_KEY_INFO_free(p8);
1626
+ if (encrypted)
1627
+ X509_SIG_free(encrypted);
1628
+ return ret;
1629
+ }
1630
+
1631
+ int pq_pkcs8_der_is_encrypted_private_key_info(const uint8_t *input, size_t input_len) {
1632
+ const unsigned char *cursor;
1633
+ X509_SIG *encrypted = NULL;
1634
+ const X509_ALGOR *alg = NULL;
1635
+ const ASN1_OCTET_STRING *digest = NULL;
1636
+ const ASN1_OBJECT *obj = NULL;
1637
+ int ptype = 0;
1638
+ const void *pval = NULL;
1639
+ int ret = 0;
1640
+
1641
+ if (!input || input_len > (size_t)LONG_MAX)
1642
+ return 0;
1643
+ cursor = input;
1644
+ encrypted = d2i_X509_SIG(NULL, &cursor, (long)input_len);
1645
+ if (!encrypted || cursor != input + input_len)
1646
+ goto cleanup;
1647
+ X509_SIG_get0(encrypted, &alg, &digest);
1648
+ if (!alg || !digest)
1649
+ goto cleanup;
1650
+ X509_ALGOR_get0(&obj, &ptype, &pval, alg);
1651
+ (void)ptype;
1652
+ (void)pval;
1653
+ if (obj && OBJ_obj2nid(obj) == NID_pbes2)
1654
+ ret = 1;
1655
+
1656
+ cleanup:
1657
+ if (encrypted)
1658
+ X509_SIG_free(encrypted);
1659
+ return ret;
1660
+ }
1661
+
1662
+ int pq_pkcs8_der_to_pem(char **output, size_t *output_len, const uint8_t *der, size_t der_len,
1663
+ int encrypted) {
1664
+ return pq_der_to_pem(encrypted ? PQ_PKCS8_ENCRYPTED_PRIVATE_KEY_PEM_LABEL
1665
+ : PQ_PKCS8_PRIVATE_KEY_PEM_LABEL,
1666
+ der, der_len, output, output_len);
1667
+ }
1668
+
1669
+ int pq_pkcs8_pem_to_der(uint8_t **der_out, size_t *der_len_out, int *encrypted_out,
1670
+ const char *input, size_t input_len) {
1671
+ int ret;
1672
+
1673
+ if (!der_out || !der_len_out || !encrypted_out || !input)
1674
+ return PQ_ERROR_BUFFER;
1675
+ *der_out = NULL;
1676
+ *der_len_out = 0;
1677
+ *encrypted_out = 0;
1678
+
1679
+ ret = pq_pem_to_der(PQ_PKCS8_PRIVATE_KEY_PEM_LABEL, input, input_len, der_out, der_len_out);
1680
+ if (ret == PQ_SUCCESS) {
1681
+ *encrypted_out = 0;
1682
+ return PQ_SUCCESS;
1683
+ }
1684
+
1685
+ ret = pq_pem_to_der(PQ_PKCS8_ENCRYPTED_PRIVATE_KEY_PEM_LABEL, input, input_len, der_out,
1686
+ der_len_out);
1687
+ if (ret == PQ_SUCCESS) {
1688
+ *encrypted_out = 1;
1689
+ return PQ_SUCCESS;
1690
+ }
1691
+ return PQ_ERROR_BUFFER;
1692
+ }
1693
+
1163
1694
  const char *pq_version(void) {
1164
1695
  return PQCRYPTO_VERSION;
1165
1696
  }