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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -0
- data/GET_STARTED.md +70 -9
- data/README.md +11 -6
- data/ext/pqcrypto/extconf.rb +2 -0
- data/ext/pqcrypto/pq_externalmu.c +23 -18
- data/ext/pqcrypto/pqcrypto_native_api.h +10 -0
- data/ext/pqcrypto/pqcrypto_ruby_secure.c +351 -48
- data/ext/pqcrypto/pqcrypto_secure.c +615 -84
- data/ext/pqcrypto/pqcrypto_secure.h +35 -10
- data/ext/pqcrypto/pqcrypto_version.h +1 -1
- data/lib/pq_crypto/hybrid_kem.rb +2 -1
- data/lib/pq_crypto/internal.rb +23 -0
- data/lib/pq_crypto/kem.rb +79 -44
- data/lib/pq_crypto/key.rb +90 -0
- data/lib/pq_crypto/pkcs8/der.rb +68 -0
- data/lib/pq_crypto/pkcs8/private_key_choice.rb +186 -0
- data/lib/pq_crypto/pkcs8.rb +61 -304
- data/lib/pq_crypto/serialization.rb +19 -29
- data/lib/pq_crypto/signature.rb +81 -51
- data/lib/pq_crypto/version.rb +1 -1
- data/lib/pq_crypto.rb +16 -4
- metadata +10 -3
|
@@ -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,
|
|
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
|
-
|
|
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 +
|
|
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
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
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 *
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
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 *
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
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(
|
|
444
|
-
|
|
445
|
-
|
|
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(
|
|
454
|
-
|
|
455
|
-
|
|
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(
|
|
464
|
-
|
|
465
|
-
|
|
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
|
}
|