pq_crypto 0.6.6 → 0.6.8

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.
@@ -265,12 +265,64 @@ cleanup:
265
265
  return PQ_ERROR_BUFFER; \
266
266
  } \
267
267
  return native##_dec(ss, ct, sk) == 0 ? PQ_SUCCESS : PQ_ERROR_DECAPSULATE; \
268
+ } \
269
+ int pq_##prefix##_check_public_key(const uint8_t *pk) { \
270
+ int rc; \
271
+ if (!pk) { \
272
+ return PQ_ERROR_BUFFER; \
273
+ } \
274
+ rc = native##_check_pk(pk); \
275
+ if (rc == 0) { \
276
+ return PQ_SUCCESS; \
277
+ } \
278
+ if (rc == -2) { \
279
+ return PQ_ERROR_NOMEM; \
280
+ } \
281
+ return PQ_ERROR_INVALID_PUBLIC_KEY; \
282
+ } \
283
+ int pq_##prefix##_check_secret_key(const uint8_t *sk) { \
284
+ int rc; \
285
+ if (!sk) { \
286
+ return PQ_ERROR_BUFFER; \
287
+ } \
288
+ rc = native##_check_sk(sk); \
289
+ if (rc == 0) { \
290
+ return PQ_SUCCESS; \
291
+ } \
292
+ if (rc == -2) { \
293
+ return PQ_ERROR_NOMEM; \
294
+ } \
295
+ return PQ_ERROR_INVALID_SECRET_KEY; \
268
296
  }
269
297
 
270
298
  PQ_MLKEM_VARIANTS(PQ_DEFINE_MLKEM_SHIMS)
271
299
 
272
300
  #undef PQ_DEFINE_MLKEM_SHIMS
273
301
 
302
+ #define PQ_DEFINE_MLDSA_CHECK_SK(prefix, native, pk_bytes) \
303
+ int pq_##prefix##_check_secret_key(const uint8_t *sk) { \
304
+ uint8_t pk[(pk_bytes)]; \
305
+ int rc; \
306
+ if (!sk) { \
307
+ return PQ_ERROR_BUFFER; \
308
+ } \
309
+ rc = native##_pk_from_sk(pk, sk); \
310
+ pq_secure_wipe(pk, sizeof(pk)); \
311
+ if (rc == 0) { \
312
+ return PQ_SUCCESS; \
313
+ } \
314
+ if (rc == -2) { \
315
+ return PQ_ERROR_NOMEM; \
316
+ } \
317
+ return PQ_ERROR_INVALID_SECRET_KEY; \
318
+ }
319
+
320
+ PQ_DEFINE_MLDSA_CHECK_SK(mldsa, pqcr_mldsa65, MLDSA65_PUBLICKEYBYTES)
321
+ PQ_DEFINE_MLDSA_CHECK_SK(mldsa44, pqcr_mldsa44, MLDSA44_PUBLICKEYBYTES)
322
+ PQ_DEFINE_MLDSA_CHECK_SK(mldsa87, pqcr_mldsa87, MLDSA87_PUBLICKEYBYTES)
323
+
324
+ #undef PQ_DEFINE_MLDSA_CHECK_SK
325
+
274
326
  static int pq_testing_mlkem_keypair_from_seed_with(uint8_t *public_key, uint8_t *secret_key,
275
327
  const uint8_t *seed, size_t seed_len,
276
328
  int (*keypair_derand)(uint8_t *, uint8_t *,
@@ -731,13 +783,46 @@ static const pq_serialization_algorithm_t *pq_find_serialization_algorithm_by_oi
731
783
  return NULL;
732
784
  }
733
785
 
786
+ static int pq_serialized_key_size(size_t oid_len, size_t key_len, size_t *total_len) {
787
+ const size_t parts[] = {8, oid_len, 4, key_len};
788
+ size_t total = 0;
789
+
790
+ for (size_t i = 0; i < sizeof(parts) / sizeof(parts[0]); ++i) {
791
+ if (pq_size_add(total, parts[i], &total) != PQ_SUCCESS)
792
+ return PQ_ERROR_BUFFER;
793
+ }
794
+ *total_len = total;
795
+ return PQ_SUCCESS;
796
+ }
797
+
798
+ static void pq_write_u16be(uint8_t *output, uint16_t value) {
799
+ output[0] = (uint8_t)(value >> 8);
800
+ output[1] = (uint8_t)value;
801
+ }
802
+
803
+ static void pq_write_u32be(uint8_t *output, uint32_t value) {
804
+ output[0] = (uint8_t)(value >> 24);
805
+ output[1] = (uint8_t)(value >> 16);
806
+ output[2] = (uint8_t)(value >> 8);
807
+ output[3] = (uint8_t)value;
808
+ }
809
+
810
+ static uint16_t pq_read_u16be(const uint8_t *input) {
811
+ return (uint16_t)(((uint16_t)input[0] << 8) | input[1]);
812
+ }
813
+
814
+ static uint32_t pq_read_u32be(const uint8_t *input) {
815
+ return ((uint32_t)input[0] << 24) | ((uint32_t)input[1] << 16) | ((uint32_t)input[2] << 8) |
816
+ input[3];
817
+ }
818
+
734
819
  static int pq_encode_serialized_key(uint8_t **output, size_t *output_len, uint8_t type,
735
820
  const uint8_t *key_bytes, size_t key_len,
736
821
  const char *algorithm) {
737
822
  const pq_serialization_algorithm_t *entry;
738
823
  size_t expected_len;
739
824
  size_t oid_len;
740
- size_t total_len = 0;
825
+ size_t total_len;
741
826
  uint8_t *buf;
742
827
  int ret;
743
828
 
@@ -762,19 +847,7 @@ static int pq_encode_serialized_key(uint8_t **output, size_t *output_len, uint8_
762
847
  if (key_len > UINT32_MAX)
763
848
  return PQ_ERROR_BUFFER;
764
849
 
765
- ret = pq_size_add(total_len, 4, &total_len);
766
- if (ret != PQ_SUCCESS)
767
- return ret;
768
- ret = pq_size_add(total_len, 1 + 1 + 2, &total_len);
769
- if (ret != PQ_SUCCESS)
770
- return ret;
771
- ret = pq_size_add(total_len, oid_len, &total_len);
772
- if (ret != PQ_SUCCESS)
773
- return ret;
774
- ret = pq_size_add(total_len, 4, &total_len);
775
- if (ret != PQ_SUCCESS)
776
- return ret;
777
- ret = pq_size_add(total_len, key_len, &total_len);
850
+ ret = pq_serialized_key_size(oid_len, key_len, &total_len);
778
851
  if (ret != PQ_SUCCESS)
779
852
  return ret;
780
853
 
@@ -788,13 +861,9 @@ static int pq_encode_serialized_key(uint8_t **output, size_t *output_len, uint8_
788
861
  buf[3] = PQC_SERIALIZATION_MAGIC_3;
789
862
  buf[4] = PQC_SERIALIZATION_VERSION;
790
863
  buf[5] = type;
791
- buf[6] = (uint8_t)((oid_len >> 8) & 0xFF);
792
- buf[7] = (uint8_t)(oid_len & 0xFF);
864
+ pq_write_u16be(buf + 6, (uint16_t)oid_len);
793
865
  memcpy(buf + 8, entry->oid, oid_len);
794
- buf[8 + oid_len + 0] = (uint8_t)((key_len >> 24) & 0xFF);
795
- buf[8 + oid_len + 1] = (uint8_t)((key_len >> 16) & 0xFF);
796
- buf[8 + oid_len + 2] = (uint8_t)((key_len >> 8) & 0xFF);
797
- buf[8 + oid_len + 3] = (uint8_t)(key_len & 0xFF);
866
+ pq_write_u32be(buf + 8 + oid_len, (uint32_t)key_len);
798
867
  memcpy(buf + 8 + oid_len + 4, key_bytes, key_len);
799
868
 
800
869
  *output = buf;
@@ -802,62 +871,92 @@ static int pq_encode_serialized_key(uint8_t **output, size_t *output_len, uint8_
802
871
  return PQ_SUCCESS;
803
872
  }
804
873
 
805
- static int pq_decode_serialized_key(const uint8_t *input, size_t input_len, uint8_t expected_type,
806
- char **algorithm_out, uint8_t **key_out, size_t *key_len_out) {
807
- uint16_t oid_len;
808
- uint32_t key_len;
809
- const pq_serialization_algorithm_t *entry;
810
- size_t offset;
811
- size_t expected_len = 0;
812
- uint8_t *key_copy = NULL;
813
- char *algorithm_copy = NULL;
814
-
815
- if (!input || !algorithm_out || !key_out || !key_len_out)
874
+ static int pq_serialized_key_header(uint8_t expected_type, const uint8_t *input, size_t input_len,
875
+ uint16_t *oid_len_out) {
876
+ if (!input || !oid_len_out)
816
877
  return PQ_ERROR_BUFFER;
817
-
818
- *algorithm_out = NULL;
819
- *key_out = NULL;
820
- *key_len_out = 0;
821
-
822
878
  if (input_len < 12)
823
879
  return PQ_ERROR_BUFFER;
824
880
  if (input[0] != PQC_SERIALIZATION_MAGIC_0 || input[1] != PQC_SERIALIZATION_MAGIC_1 ||
825
- input[2] != PQC_SERIALIZATION_MAGIC_2 || input[3] != PQC_SERIALIZATION_MAGIC_3) {
881
+ input[2] != PQC_SERIALIZATION_MAGIC_2 || input[3] != PQC_SERIALIZATION_MAGIC_3)
826
882
  return PQ_ERROR_BUFFER;
827
- }
828
883
  if (input[4] != PQC_SERIALIZATION_VERSION || input[5] != expected_type)
829
884
  return PQ_ERROR_BUFFER;
830
885
 
831
- oid_len = ((uint16_t)input[6] << 8) | (uint16_t)input[7];
832
- if (oid_len == 0)
886
+ *oid_len_out = pq_read_u16be(input + 6);
887
+ if (*oid_len_out == 0 || input_len - 8 < (size_t)*oid_len_out + 4)
833
888
  return PQ_ERROR_BUFFER;
834
- offset = 8;
835
- if (input_len < offset || input_len - offset < (size_t)oid_len + 4)
889
+ return PQ_SUCCESS;
890
+ }
891
+
892
+ static int pq_serialized_key_payload(const uint8_t *input, size_t input_len, uint8_t expected_type,
893
+ const pq_serialization_algorithm_t **entry_out,
894
+ const uint8_t **key_out, size_t *key_len_out) {
895
+ uint16_t oid_len;
896
+ uint32_t key_len;
897
+ const pq_serialization_algorithm_t *entry;
898
+ size_t offset = 8;
899
+ size_t expected_len;
900
+ int ret;
901
+
902
+ if (!entry_out || !key_out || !key_len_out)
836
903
  return PQ_ERROR_BUFFER;
904
+ *entry_out = NULL;
905
+ *key_out = NULL;
906
+ *key_len_out = 0;
907
+
908
+ ret = pq_serialized_key_header(expected_type, input, input_len, &oid_len);
909
+ if (ret != PQ_SUCCESS)
910
+ return ret;
837
911
  entry = pq_find_serialization_algorithm_by_oid((const char *)(input + offset), oid_len);
838
912
  if (!entry)
839
913
  return PQ_ERROR_BUFFER;
840
914
  offset += oid_len;
841
- key_len = ((uint32_t)input[offset + 0] << 24) | ((uint32_t)input[offset + 1] << 16) |
842
- ((uint32_t)input[offset + 2] << 8) | (uint32_t)input[offset + 3];
915
+ key_len = pq_read_u32be(input + offset);
843
916
  offset += 4;
844
- if (input_len < offset || input_len - offset != (size_t)key_len)
917
+ if (input_len - offset != (size_t)key_len)
845
918
  return PQ_ERROR_BUFFER;
846
919
  expected_len = (expected_type == PQC_SERIALIZATION_TYPE_PUBLIC) ? entry->public_key_len
847
920
  : entry->secret_key_len;
848
921
  if ((size_t)key_len != expected_len)
849
922
  return PQ_ERROR_BUFFER;
850
923
 
851
- key_copy = malloc((size_t)key_len);
924
+ *entry_out = entry;
925
+ *key_out = input + offset;
926
+ *key_len_out = (size_t)key_len;
927
+ return PQ_SUCCESS;
928
+ }
929
+
930
+ static int pq_decode_serialized_key(const uint8_t *input, size_t input_len, uint8_t expected_type,
931
+ char **algorithm_out, uint8_t **key_out, size_t *key_len_out) {
932
+ const pq_serialization_algorithm_t *entry = NULL;
933
+ const uint8_t *key_data = NULL;
934
+ size_t key_len = 0;
935
+ uint8_t *key_copy = NULL;
936
+ char *algorithm_copy = NULL;
937
+ int ret;
938
+
939
+ if (!input || !algorithm_out || !key_out || !key_len_out)
940
+ return PQ_ERROR_BUFFER;
941
+
942
+ *algorithm_out = NULL;
943
+ *key_out = NULL;
944
+ *key_len_out = 0;
945
+
946
+ ret = pq_serialized_key_payload(input, input_len, expected_type, &entry, &key_data, &key_len);
947
+ if (ret != PQ_SUCCESS)
948
+ return ret;
949
+
950
+ key_copy = malloc(key_len);
852
951
  if (!key_copy)
853
952
  return PQ_ERROR_NOMEM;
854
- memcpy(key_copy, input + offset, (size_t)key_len);
953
+ memcpy(key_copy, key_data, key_len);
855
954
 
856
955
  {
857
956
  size_t algorithm_len = strlen(entry->algorithm);
858
957
  algorithm_copy = malloc(algorithm_len + 1);
859
958
  if (!algorithm_copy) {
860
- pq_secure_wipe(key_copy, (size_t)key_len);
959
+ pq_secure_wipe(key_copy, key_len);
861
960
  free(key_copy);
862
961
  return PQ_ERROR_NOMEM;
863
962
  }
@@ -866,7 +965,7 @@ static int pq_decode_serialized_key(const uint8_t *input, size_t input_len, uint
866
965
 
867
966
  *algorithm_out = algorithm_copy;
868
967
  *key_out = key_copy;
869
- *key_len_out = (size_t)key_len;
968
+ *key_len_out = key_len;
870
969
  return PQ_SUCCESS;
871
970
  }
872
971
 
@@ -898,6 +997,143 @@ static const char *pq_find_pem_footer(const char *start, size_t len, const char
898
997
  return NULL;
899
998
  }
900
999
 
1000
+ static int pq_pem_body_bounds(const char *label, const char *input, size_t input_len,
1001
+ const char **body_start_out, size_t *body_len_out) {
1002
+ char header[64], footer[64];
1003
+ int header_len, footer_len;
1004
+ const char *body_start, *footer_pos, *tail;
1005
+
1006
+ if (!label || !input || !body_start_out || !body_len_out)
1007
+ return PQ_ERROR_BUFFER;
1008
+ header_len = snprintf(header, sizeof(header), "-----BEGIN %s-----", label);
1009
+ footer_len = snprintf(footer, sizeof(footer), "-----END %s-----", label);
1010
+ if (header_len <= 0 || footer_len <= 0 ||
1011
+ input_len < (size_t)header_len + (size_t)footer_len + 2 ||
1012
+ strncmp(input, header, (size_t)header_len) != 0)
1013
+ return PQ_ERROR_BUFFER;
1014
+
1015
+ body_start = input + header_len;
1016
+ while ((size_t)(body_start - input) < input_len && pq_is_pem_whitespace(*body_start))
1017
+ body_start++;
1018
+ footer_pos = pq_find_pem_footer(body_start, input_len - (size_t)(body_start - input), footer,
1019
+ (size_t)footer_len);
1020
+ if (!footer_pos)
1021
+ return PQ_ERROR_BUFFER;
1022
+
1023
+ tail = footer_pos + footer_len;
1024
+ while ((size_t)(tail - input) < input_len) {
1025
+ if (!pq_is_pem_whitespace(*tail))
1026
+ return PQ_ERROR_BUFFER;
1027
+ tail++;
1028
+ }
1029
+
1030
+ *body_len_out = (size_t)(footer_pos - body_start);
1031
+ if (*body_len_out > (size_t)INT_MAX)
1032
+ return PQ_ERROR_BUFFER;
1033
+ *body_start_out = body_start;
1034
+ return PQ_SUCCESS;
1035
+ }
1036
+
1037
+ static int pq_pem_compact_body(const char *body_start, size_t body_len, unsigned char **compact_out,
1038
+ size_t *compact_len_out) {
1039
+ unsigned char *compact;
1040
+ size_t compact_len = 0;
1041
+ int padding = 0;
1042
+ int saw_padding = 0;
1043
+
1044
+ compact = malloc(body_len ? body_len : 1);
1045
+ if (!compact)
1046
+ return PQ_ERROR_NOMEM;
1047
+
1048
+ for (size_t i = 0; i < body_len; ++i) {
1049
+ unsigned char c = (unsigned char)body_start[i];
1050
+ int value;
1051
+
1052
+ if (pq_is_pem_whitespace((char)c))
1053
+ continue;
1054
+ value = pq_base64_char_value(c);
1055
+ if (value < 0)
1056
+ goto invalid;
1057
+ if (c == '=') {
1058
+ saw_padding = 1;
1059
+ if (++padding > 2)
1060
+ goto invalid;
1061
+ } else if (saw_padding)
1062
+ goto invalid;
1063
+ compact[compact_len++] = c;
1064
+ }
1065
+
1066
+ if (compact_len == 0 || (compact_len % 4) != 0 || compact_len > (size_t)INT_MAX) {
1067
+ goto invalid;
1068
+ }
1069
+ *compact_out = compact;
1070
+ *compact_len_out = compact_len;
1071
+ return PQ_SUCCESS;
1072
+
1073
+ invalid:
1074
+ pq_secure_wipe(compact, body_len);
1075
+ free(compact);
1076
+ return PQ_ERROR_BUFFER;
1077
+ }
1078
+
1079
+ static int pq_base64_encode_der(const uint8_t *der, size_t der_len, unsigned char **encoded_out,
1080
+ size_t *encoded_len_out) {
1081
+ size_t encoded_len;
1082
+ unsigned char *encoded;
1083
+
1084
+ if (der_len > (size_t)INT_MAX)
1085
+ return PQ_ERROR_BUFFER;
1086
+ encoded_len = 4 * ((der_len + 2) / 3);
1087
+ if (encoded_len > (size_t)INT_MAX)
1088
+ return PQ_ERROR_BUFFER;
1089
+ encoded = malloc(encoded_len + 1);
1090
+ if (!encoded)
1091
+ return PQ_ERROR_NOMEM;
1092
+ if (EVP_EncodeBlock(encoded, der, (int)der_len) != (int)encoded_len) {
1093
+ pq_secure_wipe(encoded, encoded_len + 1);
1094
+ free(encoded);
1095
+ return PQ_ERROR_OPENSSL;
1096
+ }
1097
+ *encoded_out = encoded;
1098
+ *encoded_len_out = encoded_len;
1099
+ return PQ_SUCCESS;
1100
+ }
1101
+
1102
+ static int pq_pem_encoded_size(size_t header_len, size_t encoded_len, size_t line_count,
1103
+ size_t footer_len, size_t *needed_out) {
1104
+ const size_t parts[] = {header_len, 1, encoded_len, line_count, footer_len, 1};
1105
+ size_t needed = 0;
1106
+
1107
+ for (size_t i = 0; i < sizeof(parts) / sizeof(parts[0]); ++i) {
1108
+ if (pq_size_add(needed, parts[i], &needed) != PQ_SUCCESS)
1109
+ return PQ_ERROR_BUFFER;
1110
+ }
1111
+ *needed_out = needed;
1112
+ return PQ_SUCCESS;
1113
+ }
1114
+
1115
+ static size_t pq_write_pem_body(char *output, const char *header, size_t header_len,
1116
+ const unsigned char *encoded, size_t encoded_len,
1117
+ const char *footer, size_t footer_len) {
1118
+ char *cursor = output;
1119
+
1120
+ memcpy(cursor, header, header_len);
1121
+ cursor += header_len;
1122
+ *cursor++ = '\n';
1123
+ for (size_t offset = 0; offset < encoded_len; offset += 64) {
1124
+ size_t line_len = encoded_len - offset;
1125
+ if (line_len > 64)
1126
+ line_len = 64;
1127
+ memcpy(cursor, encoded + offset, line_len);
1128
+ cursor += line_len;
1129
+ *cursor++ = '\n';
1130
+ }
1131
+ memcpy(cursor, footer, footer_len);
1132
+ cursor += footer_len;
1133
+ *cursor = '\0';
1134
+ return (size_t)(cursor - output);
1135
+ }
1136
+
901
1137
  static int pq_der_to_pem(const char *label, const uint8_t *der, size_t der_len, char **output,
902
1138
  size_t *output_len) {
903
1139
  char header[64];
@@ -908,7 +1144,7 @@ static int pq_der_to_pem(const char *label, const uint8_t *der, size_t der_len,
908
1144
  size_t encoded_len;
909
1145
  size_t line_count;
910
1146
  size_t needed;
911
- char *cur;
1147
+ int ret;
912
1148
 
913
1149
  if (!label || !der || !output || !output_len)
914
1150
  return PQ_ERROR_BUFFER;
@@ -919,32 +1155,18 @@ static int pq_der_to_pem(const char *label, const uint8_t *der, size_t der_len,
919
1155
  footer_len = snprintf(footer, sizeof(footer), "-----END %s-----", label);
920
1156
  if (header_len <= 0 || footer_len <= 0)
921
1157
  return PQ_ERROR_BUFFER;
922
- if (der_len > (size_t)INT_MAX)
923
- return PQ_ERROR_BUFFER;
924
-
925
- encoded_len = 4 * ((der_len + 2) / 3);
926
- if (encoded_len > (size_t)INT_MAX)
927
- return PQ_ERROR_BUFFER;
928
-
929
- encoded = malloc(encoded_len + 1);
930
- if (!encoded)
931
- return PQ_ERROR_NOMEM;
932
-
933
- if (EVP_EncodeBlock(encoded, der, (int)der_len) != (int)encoded_len) {
934
- pq_secure_wipe(encoded, encoded_len + 1);
935
- free(encoded);
936
- return PQ_ERROR_OPENSSL;
937
- }
1158
+ ret = pq_base64_encode_der(der, der_len, &encoded, &encoded_len);
1159
+ if (ret != PQ_SUCCESS)
1160
+ return ret;
938
1161
 
939
1162
  line_count = encoded_len == 0 ? 0 : ((encoded_len + 63) / 64);
940
- if (SIZE_MAX - (size_t)header_len < 1 || SIZE_MAX - ((size_t)header_len + 1) < encoded_len ||
941
- SIZE_MAX - ((size_t)header_len + 1 + encoded_len) < line_count ||
942
- SIZE_MAX - ((size_t)header_len + 1 + encoded_len + line_count) < (size_t)footer_len + 1) {
1163
+ ret = pq_pem_encoded_size((size_t)header_len, encoded_len, line_count, (size_t)footer_len,
1164
+ &needed);
1165
+ if (ret != PQ_SUCCESS) {
943
1166
  pq_secure_wipe(encoded, encoded_len + 1);
944
1167
  free(encoded);
945
- return PQ_ERROR_BUFFER;
1168
+ return ret;
946
1169
  }
947
- needed = (size_t)header_len + 1 + encoded_len + line_count + (size_t)footer_len + 1;
948
1170
 
949
1171
  pem = malloc(needed);
950
1172
  if (!pem) {
@@ -953,26 +1175,9 @@ static int pq_der_to_pem(const char *label, const uint8_t *der, size_t der_len,
953
1175
  return PQ_ERROR_NOMEM;
954
1176
  }
955
1177
 
956
- cur = pem;
957
- memcpy(cur, header, (size_t)header_len);
958
- cur += header_len;
959
- *cur++ = '\n';
960
-
961
- for (size_t offset = 0; offset < encoded_len; offset += 64) {
962
- size_t line_len = encoded_len - offset;
963
- if (line_len > 64)
964
- line_len = 64;
965
- memcpy(cur, encoded + offset, line_len);
966
- cur += line_len;
967
- *cur++ = '\n';
968
- }
969
-
970
- memcpy(cur, footer, (size_t)footer_len);
971
- cur += footer_len;
972
- *cur = '\0';
973
-
974
1178
  *output = pem;
975
- *output_len = (size_t)(cur - pem);
1179
+ *output_len = pq_write_pem_body(pem, header, (size_t)header_len, encoded, encoded_len, footer,
1180
+ (size_t)footer_len);
976
1181
  pq_secure_wipe(encoded, encoded_len + 1);
977
1182
  free(encoded);
978
1183
  return PQ_SUCCESS;
@@ -980,10 +1185,7 @@ static int pq_der_to_pem(const char *label, const uint8_t *der, size_t der_len,
980
1185
 
981
1186
  static int pq_pem_to_der(const char *label, const char *input, size_t input_len, uint8_t **der_out,
982
1187
  size_t *der_len_out) {
983
- char header[64], footer[64];
984
- int header_len, footer_len;
985
- const char *body_start, *footer_pos;
986
- const char *tail;
1188
+ const char *body_start;
987
1189
  uint8_t *der = NULL;
988
1190
  unsigned char *compact = NULL;
989
1191
  size_t body_len = 0;
@@ -991,79 +1193,21 @@ static int pq_pem_to_der(const char *label, const char *input, size_t input_len,
991
1193
  size_t der_cap = 0;
992
1194
  int decoded_len = 0;
993
1195
  int padding = 0;
994
- int saw_padding = 0;
1196
+ int ret;
995
1197
 
996
1198
  if (!label || !input || !der_out || !der_len_out)
997
1199
  return PQ_ERROR_BUFFER;
998
1200
  *der_out = NULL;
999
1201
  *der_len_out = 0;
1000
1202
 
1001
- header_len = snprintf(header, sizeof(header), "-----BEGIN %s-----", label);
1002
- footer_len = snprintf(footer, sizeof(footer), "-----END %s-----", label);
1003
- if (header_len <= 0 || footer_len <= 0)
1004
- return PQ_ERROR_BUFFER;
1005
- if (input_len < (size_t)(header_len + footer_len + 2))
1006
- return PQ_ERROR_BUFFER;
1007
- if (strncmp(input, header, (size_t)header_len) != 0)
1008
- return PQ_ERROR_BUFFER;
1009
-
1010
- body_start = input + header_len;
1011
- while ((size_t)(body_start - input) < input_len && pq_is_pem_whitespace(*body_start))
1012
- body_start++;
1013
-
1014
- footer_pos = pq_find_pem_footer(body_start, input_len - (size_t)(body_start - input), footer,
1015
- (size_t)footer_len);
1016
- if (!footer_pos)
1017
- return PQ_ERROR_BUFFER;
1018
-
1019
- tail = footer_pos + footer_len;
1020
- while ((size_t)(tail - input) < input_len) {
1021
- if (!pq_is_pem_whitespace(*tail))
1022
- return PQ_ERROR_BUFFER;
1023
- tail++;
1024
- }
1025
-
1026
- body_len = (size_t)(footer_pos - body_start);
1027
- if (body_len > (size_t)INT_MAX)
1028
- return PQ_ERROR_BUFFER;
1029
-
1030
- compact = malloc(body_len ? body_len : 1);
1031
- if (!compact)
1032
- return PQ_ERROR_NOMEM;
1033
-
1034
- for (size_t i = 0; i < body_len; ++i) {
1035
- unsigned char c = (unsigned char)body_start[i];
1036
- int value;
1037
- if (pq_is_pem_whitespace((char)c))
1038
- continue;
1039
-
1040
- value = pq_base64_char_value(c);
1041
- if (value < 0) {
1042
- pq_secure_wipe(compact, body_len);
1043
- free(compact);
1044
- return PQ_ERROR_BUFFER;
1045
- }
1046
- if (c == '=') {
1047
- saw_padding = 1;
1048
- padding++;
1049
- if (padding > 2) {
1050
- pq_secure_wipe(compact, body_len);
1051
- free(compact);
1052
- return PQ_ERROR_BUFFER;
1053
- }
1054
- } else if (saw_padding) {
1055
- pq_secure_wipe(compact, body_len);
1056
- free(compact);
1057
- return PQ_ERROR_BUFFER;
1058
- }
1059
- compact[compact_len++] = c;
1060
- }
1061
-
1062
- if (compact_len == 0 || (compact_len % 4) != 0 || compact_len > (size_t)INT_MAX) {
1063
- pq_secure_wipe(compact, body_len);
1064
- free(compact);
1065
- return PQ_ERROR_BUFFER;
1066
- }
1203
+ ret = pq_pem_body_bounds(label, input, input_len, &body_start, &body_len);
1204
+ if (ret != PQ_SUCCESS)
1205
+ return ret;
1206
+ ret = pq_pem_compact_body(body_start, body_len, &compact, &compact_len);
1207
+ if (ret != PQ_SUCCESS)
1208
+ return ret;
1209
+ for (size_t i = compact_len; i > 0 && compact[i - 1] == '='; --i)
1210
+ padding++;
1067
1211
 
1068
1212
  der_cap = (compact_len / 4) * 3;
1069
1213
  der = malloc(der_cap ? der_cap : 1);
@@ -1356,11 +1500,224 @@ cleanup:
1356
1500
  return ret;
1357
1501
  }
1358
1502
 
1503
+ static int pq_der_tlv_size(size_t value_len, size_t *tlv_len_out) {
1504
+ size_t header_len;
1505
+
1506
+ if (pq_size_add(1, pq_der_length_octets(value_len), &header_len) != PQ_SUCCESS ||
1507
+ pq_size_add(header_len, value_len, tlv_len_out) != PQ_SUCCESS)
1508
+ return PQ_ERROR_BUFFER;
1509
+ return PQ_SUCCESS;
1510
+ }
1511
+
1512
+ static int pq_der_write_tlv_header(uint8_t tag, uint8_t **cursor, size_t value_len) {
1513
+ if (!cursor || !*cursor)
1514
+ return PQ_ERROR_BUFFER;
1515
+ *(*cursor)++ = tag;
1516
+ return pq_der_write_length(cursor, value_len);
1517
+ }
1518
+
1519
+ static int pq_der_write_tlv(uint8_t **cursor, uint8_t tag, const uint8_t *value, size_t value_len) {
1520
+ int ret = pq_der_write_tlv_header(tag, cursor, value_len);
1521
+
1522
+ if (ret != PQ_SUCCESS)
1523
+ return ret;
1524
+ if (value_len > 0) {
1525
+ if (!value)
1526
+ return PQ_ERROR_BUFFER;
1527
+ memcpy(*cursor, value, value_len);
1528
+ *cursor += value_len;
1529
+ }
1530
+ return PQ_SUCCESS;
1531
+ }
1532
+
1533
+ typedef struct {
1534
+ size_t inner_len;
1535
+ size_t total_len;
1536
+ } pq_pkcs8_size_t;
1537
+
1538
+ static int pq_pkcs8_private_key_info_size(size_t oid_len, size_t private_key_len,
1539
+ pq_pkcs8_size_t *size_out) {
1540
+ size_t algorithm_len, private_len, inner_len, total_len;
1541
+
1542
+ if (pq_der_tlv_size(oid_len, &algorithm_len) != PQ_SUCCESS ||
1543
+ pq_der_tlv_size(private_key_len, &private_len) != PQ_SUCCESS ||
1544
+ pq_size_add(3, algorithm_len, &inner_len) != PQ_SUCCESS ||
1545
+ pq_size_add(inner_len, private_len, &inner_len) != PQ_SUCCESS ||
1546
+ pq_der_tlv_size(inner_len, &total_len) != PQ_SUCCESS)
1547
+ return PQ_ERROR_BUFFER;
1548
+ size_out->inner_len = inner_len;
1549
+ size_out->total_len = total_len;
1550
+ return PQ_SUCCESS;
1551
+ }
1552
+
1553
+ typedef struct {
1554
+ size_t oid_offset;
1555
+ size_t oid_tlv_len;
1556
+ size_t private_key_offset;
1557
+ size_t private_key_len;
1558
+ size_t outer_end;
1559
+ size_t content_offset;
1560
+ } pq_pkcs8_parts_t;
1561
+
1562
+ static int pq_pkcs8_parse_outer(const uint8_t *input, size_t input_len, pq_pkcs8_parts_t *parts) {
1563
+ size_t offset = 0, outer_offset = 0, outer_len = 0;
1564
+ size_t version_offset = 0, version_len = 0;
1565
+ int ret;
1566
+
1567
+ ret = pq_der_expect_tlv(input, input_len, &offset, 0x30, &outer_offset, &outer_len);
1568
+ if (ret != PQ_SUCCESS)
1569
+ return ret;
1570
+ if (offset != input_len ||
1571
+ pq_size_add(outer_offset, outer_len, &parts->outer_end) != PQ_SUCCESS ||
1572
+ parts->outer_end != input_len)
1573
+ return PQ_ERROR_BUFFER;
1574
+ offset = outer_offset;
1575
+ ret = pq_der_expect_tlv(input, parts->outer_end, &offset, 0x02, &version_offset, &version_len);
1576
+ if (ret != PQ_SUCCESS)
1577
+ return ret;
1578
+ if (version_len != 1 || input[version_offset] != 0)
1579
+ return PQ_ERROR_BUFFER;
1580
+ parts->content_offset = offset;
1581
+ return PQ_SUCCESS;
1582
+ }
1583
+
1584
+ static int pq_pkcs8_parse_algorithm(const uint8_t *input, size_t outer_end, size_t *offset,
1585
+ pq_pkcs8_parts_t *parts) {
1586
+ size_t alg_offset = 0, alg_len = 0, alg_end;
1587
+ size_t alg_cursor, oid_offset = 0, oid_len = 0;
1588
+ int ret;
1589
+
1590
+ ret = pq_der_expect_tlv(input, outer_end, offset, 0x30, &alg_offset, &alg_len);
1591
+ if (ret != PQ_SUCCESS || pq_size_add(alg_offset, alg_len, &alg_end) != PQ_SUCCESS)
1592
+ return PQ_ERROR_BUFFER;
1593
+ alg_cursor = alg_offset;
1594
+ parts->oid_offset = alg_cursor;
1595
+ ret = pq_der_expect_tlv(input, alg_end, &alg_cursor, 0x06, &oid_offset, &oid_len);
1596
+ if (ret != PQ_SUCCESS || alg_cursor != alg_end)
1597
+ return PQ_ERROR_BUFFER;
1598
+ parts->oid_tlv_len = alg_cursor - parts->oid_offset;
1599
+ return PQ_SUCCESS;
1600
+ }
1601
+
1602
+ static int pq_pkcs8_parse_parts(const uint8_t *input, size_t input_len, pq_pkcs8_parts_t *parts) {
1603
+ size_t offset;
1604
+ int ret = pq_pkcs8_parse_outer(input, input_len, parts);
1605
+
1606
+ if (ret != PQ_SUCCESS)
1607
+ return ret;
1608
+ offset = parts->content_offset;
1609
+ ret = pq_pkcs8_parse_algorithm(input, parts->outer_end, &offset, parts);
1610
+ if (ret != PQ_SUCCESS)
1611
+ return ret;
1612
+ ret = pq_der_expect_tlv(input, parts->outer_end, &offset, 0x04, &parts->private_key_offset,
1613
+ &parts->private_key_len);
1614
+ if (ret != PQ_SUCCESS || offset != parts->outer_end)
1615
+ return PQ_ERROR_BUFFER;
1616
+ return PQ_SUCCESS;
1617
+ }
1618
+
1619
+ static int pq_x509_sig_to_der(X509_SIG *encrypted, unsigned char **der_out, size_t *der_len_out) {
1620
+ unsigned char *der;
1621
+ unsigned char *cursor;
1622
+ int der_len = i2d_X509_SIG(encrypted, NULL);
1623
+
1624
+ if (der_len <= 0)
1625
+ return PQ_ERROR_OPENSSL;
1626
+ der = malloc((size_t)der_len);
1627
+ if (!der)
1628
+ return PQ_ERROR_NOMEM;
1629
+ cursor = der;
1630
+ if (i2d_X509_SIG(encrypted, &cursor) != der_len || (size_t)(cursor - der) != (size_t)der_len) {
1631
+ pq_secure_wipe(der, (size_t)der_len);
1632
+ free(der);
1633
+ return PQ_ERROR_OPENSSL;
1634
+ }
1635
+ *der_out = der;
1636
+ *der_len_out = (size_t)der_len;
1637
+ return PQ_SUCCESS;
1638
+ }
1639
+
1640
+ static int pq_pkcs8_info_to_der(PKCS8_PRIV_KEY_INFO *p8, unsigned char **der_out,
1641
+ size_t *der_len_out) {
1642
+ unsigned char *der;
1643
+ unsigned char *cursor;
1644
+ int der_len = i2d_PKCS8_PRIV_KEY_INFO(p8, NULL);
1645
+
1646
+ if (der_len <= 0)
1647
+ return PQ_ERROR_OPENSSL;
1648
+ der = malloc((size_t)der_len);
1649
+ if (!der)
1650
+ return PQ_ERROR_NOMEM;
1651
+ cursor = der;
1652
+ if (i2d_PKCS8_PRIV_KEY_INFO(p8, &cursor) != der_len ||
1653
+ (size_t)(cursor - der) != (size_t)der_len) {
1654
+ pq_secure_wipe(der, (size_t)der_len);
1655
+ free(der);
1656
+ return PQ_ERROR_OPENSSL;
1657
+ }
1658
+ *der_out = der;
1659
+ *der_len_out = (size_t)der_len;
1660
+ return PQ_SUCCESS;
1661
+ }
1662
+
1663
+ static int pq_pkcs8_encrypt(const uint8_t *plain_der, size_t plain_der_len, const char *passphrase,
1664
+ size_t passphrase_len, int iterations, X509_SIG **encrypted_out) {
1665
+ const unsigned char *cursor = plain_der;
1666
+ PKCS8_PRIV_KEY_INFO *p8 = NULL;
1667
+ X509_SIG *encrypted = NULL;
1668
+ unsigned char salt[16];
1669
+ int ret = PQ_ERROR_OPENSSL;
1670
+
1671
+ p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &cursor, (long)plain_der_len);
1672
+ if (!p8 || cursor != plain_der + plain_der_len || RAND_bytes(salt, sizeof(salt)) != 1)
1673
+ goto cleanup;
1674
+ encrypted = PKCS8_encrypt(-1, EVP_aes_256_cbc(), passphrase, (int)passphrase_len, salt,
1675
+ (int)sizeof(salt), iterations, p8);
1676
+ if (!encrypted)
1677
+ goto cleanup;
1678
+ *encrypted_out = encrypted;
1679
+ encrypted = NULL;
1680
+ ret = PQ_SUCCESS;
1681
+
1682
+ cleanup:
1683
+ pq_secure_wipe(salt, sizeof(salt));
1684
+ if (encrypted)
1685
+ X509_SIG_free(encrypted);
1686
+ if (p8)
1687
+ PKCS8_PRIV_KEY_INFO_free(p8);
1688
+ return ret;
1689
+ }
1690
+
1691
+ static int pq_pkcs8_decrypt(const uint8_t *encrypted_der, size_t encrypted_der_len,
1692
+ const char *passphrase, size_t passphrase_len,
1693
+ PKCS8_PRIV_KEY_INFO **p8_out) {
1694
+ const unsigned char *cursor = encrypted_der;
1695
+ X509_SIG *encrypted = d2i_X509_SIG(NULL, &cursor, (long)encrypted_der_len);
1696
+ PKCS8_PRIV_KEY_INFO *p8 = NULL;
1697
+ int ret = PQ_ERROR_OPENSSL;
1698
+
1699
+ if (!encrypted || cursor != encrypted_der + encrypted_der_len)
1700
+ goto cleanup;
1701
+ p8 = PKCS8_decrypt(encrypted, passphrase, (int)passphrase_len);
1702
+ if (!p8)
1703
+ goto cleanup;
1704
+ *p8_out = p8;
1705
+ p8 = NULL;
1706
+ ret = PQ_SUCCESS;
1707
+
1708
+ cleanup:
1709
+ if (p8)
1710
+ PKCS8_PRIV_KEY_INFO_free(p8);
1711
+ if (encrypted)
1712
+ X509_SIG_free(encrypted);
1713
+ return ret;
1714
+ }
1715
+
1359
1716
  int pq_pkcs8_private_key_info_to_der(uint8_t **output, size_t *output_len, const char *oid_text,
1360
1717
  const uint8_t *private_key, size_t private_key_len) {
1361
1718
  uint8_t *oid_der = NULL;
1362
1719
  size_t oid_der_len = 0;
1363
- size_t alg_body_len, alg_len, priv_len, inner_len, total_len;
1720
+ pq_pkcs8_size_t der_size = {0};
1364
1721
  uint8_t *buf = NULL;
1365
1722
  uint8_t *cur;
1366
1723
  int ret;
@@ -1374,58 +1731,42 @@ int pq_pkcs8_private_key_info_to_der(uint8_t **output, size_t *output_len, const
1374
1731
  if (ret != PQ_SUCCESS)
1375
1732
  return ret;
1376
1733
 
1377
- alg_body_len = oid_der_len;
1378
- alg_len = 1 + pq_der_length_octets(alg_body_len) + alg_body_len;
1379
- priv_len = 1 + pq_der_length_octets(private_key_len) + private_key_len;
1380
- if (pq_size_add(3, alg_len, &inner_len) != PQ_SUCCESS ||
1381
- pq_size_add(inner_len, priv_len, &inner_len) != PQ_SUCCESS) {
1382
- ret = PQ_ERROR_BUFFER;
1383
- goto cleanup;
1384
- }
1385
- if (pq_size_add(1 + pq_der_length_octets(inner_len), inner_len, &total_len) != PQ_SUCCESS) {
1386
- ret = PQ_ERROR_BUFFER;
1734
+ ret = pq_pkcs8_private_key_info_size(oid_der_len, private_key_len, &der_size);
1735
+ if (ret != PQ_SUCCESS)
1387
1736
  goto cleanup;
1388
- }
1389
1737
 
1390
- buf = malloc(total_len);
1738
+ buf = malloc(der_size.total_len);
1391
1739
  if (!buf) {
1392
1740
  ret = PQ_ERROR_NOMEM;
1393
1741
  goto cleanup;
1394
1742
  }
1395
1743
 
1396
1744
  cur = buf;
1397
- *cur++ = 0x30;
1398
- ret = pq_der_write_length(&cur, inner_len);
1745
+ ret = pq_der_write_tlv_header(0x30, &cur, der_size.inner_len);
1399
1746
  if (ret != PQ_SUCCESS)
1400
1747
  goto cleanup;
1401
1748
  *cur++ = 0x02;
1402
1749
  *cur++ = 0x01;
1403
1750
  *cur++ = 0x00;
1404
- *cur++ = 0x30;
1405
- ret = pq_der_write_length(&cur, alg_body_len);
1751
+ ret = pq_der_write_tlv(&cur, 0x30, oid_der, oid_der_len);
1406
1752
  if (ret != PQ_SUCCESS)
1407
1753
  goto cleanup;
1408
- memcpy(cur, oid_der, oid_der_len);
1409
- cur += oid_der_len;
1410
- *cur++ = 0x04;
1411
- ret = pq_der_write_length(&cur, private_key_len);
1754
+ ret = pq_der_write_tlv(&cur, 0x04, private_key, private_key_len);
1412
1755
  if (ret != PQ_SUCCESS)
1413
1756
  goto cleanup;
1414
- memcpy(cur, private_key, private_key_len);
1415
- cur += private_key_len;
1416
- if ((size_t)(cur - buf) != total_len) {
1757
+ if ((size_t)(cur - buf) != der_size.total_len) {
1417
1758
  ret = PQ_ERROR_BUFFER;
1418
1759
  goto cleanup;
1419
1760
  }
1420
1761
 
1421
1762
  *output = buf;
1422
- *output_len = total_len;
1763
+ *output_len = der_size.total_len;
1423
1764
  buf = NULL;
1424
1765
  ret = PQ_SUCCESS;
1425
1766
 
1426
1767
  cleanup:
1427
1768
  if (buf) {
1428
- pq_secure_wipe(buf, total_len);
1769
+ pq_secure_wipe(buf, der_size.total_len);
1429
1770
  free(buf);
1430
1771
  }
1431
1772
  if (oid_der) {
@@ -1438,11 +1779,7 @@ cleanup:
1438
1779
  int pq_pkcs8_private_key_info_from_der(char **oid_text_out, uint8_t **private_key_out,
1439
1780
  size_t *private_key_len_out, const uint8_t *input,
1440
1781
  size_t input_len) {
1441
- size_t offset = 0;
1442
- size_t outer_off = 0, outer_len = 0, outer_end;
1443
- size_t alg_off = 0, alg_len = 0, alg_end;
1444
- size_t oid_off = 0, oid_len = 0;
1445
- size_t priv_off = 0, priv_len = 0;
1782
+ pq_pkcs8_parts_t parts = {0};
1446
1783
  uint8_t *private_key = NULL;
1447
1784
  char *oid_text = NULL;
1448
1785
  int ret;
@@ -1453,58 +1790,23 @@ int pq_pkcs8_private_key_info_from_der(char **oid_text_out, uint8_t **private_ke
1453
1790
  *private_key_out = NULL;
1454
1791
  *private_key_len_out = 0;
1455
1792
 
1456
- ret = pq_der_expect_tlv(input, input_len, &offset, 0x30, &outer_off, &outer_len);
1457
- if (ret != PQ_SUCCESS)
1458
- return ret;
1459
- outer_end = outer_off + outer_len;
1460
- if (offset != input_len || outer_end != input_len)
1461
- return PQ_ERROR_BUFFER;
1462
-
1463
- offset = outer_off;
1464
- {
1465
- size_t version_off = 0, version_len = 0;
1466
- ret = pq_der_expect_tlv(input, outer_end, &offset, 0x02, &version_off, &version_len);
1467
- if (ret != PQ_SUCCESS)
1468
- return ret;
1469
- if (version_len != 1 || input[version_off] != 0x00)
1470
- return PQ_ERROR_BUFFER;
1471
- }
1472
-
1473
- ret = pq_der_expect_tlv(input, outer_end, &offset, 0x30, &alg_off, &alg_len);
1793
+ ret = pq_pkcs8_parse_parts(input, input_len, &parts);
1474
1794
  if (ret != PQ_SUCCESS)
1475
1795
  return ret;
1476
- alg_end = alg_off + alg_len;
1477
- {
1478
- size_t alg_cursor = alg_off;
1479
- size_t oid_tlv_start = alg_cursor;
1480
- ret = pq_der_expect_tlv(input, alg_end, &alg_cursor, 0x06, &oid_off, &oid_len);
1481
- if (ret != PQ_SUCCESS)
1482
- return ret;
1483
- if (alg_cursor != alg_end)
1484
- return PQ_ERROR_BUFFER;
1485
- ret = pq_oid_der_to_text(input + oid_tlv_start, alg_cursor - oid_tlv_start, &oid_text);
1486
- }
1796
+ ret = pq_oid_der_to_text(input + parts.oid_offset, parts.oid_tlv_len, &oid_text);
1487
1797
  if (ret != PQ_SUCCESS)
1488
1798
  return ret;
1489
-
1490
- ret = pq_der_expect_tlv(input, outer_end, &offset, 0x04, &priv_off, &priv_len);
1491
- if (ret != PQ_SUCCESS)
1492
- goto cleanup;
1493
- if (offset != outer_end) {
1494
- ret = PQ_ERROR_BUFFER;
1495
- goto cleanup;
1496
- }
1497
- private_key = malloc(priv_len ? priv_len : 1);
1799
+ private_key = malloc(parts.private_key_len ? parts.private_key_len : 1);
1498
1800
  if (!private_key) {
1499
1801
  ret = PQ_ERROR_NOMEM;
1500
1802
  goto cleanup;
1501
1803
  }
1502
- if (priv_len)
1503
- memcpy(private_key, input + priv_off, priv_len);
1804
+ if (parts.private_key_len)
1805
+ memcpy(private_key, input + parts.private_key_offset, parts.private_key_len);
1504
1806
 
1505
1807
  *oid_text_out = oid_text;
1506
1808
  *private_key_out = private_key;
1507
- *private_key_len_out = priv_len;
1809
+ *private_key_len_out = parts.private_key_len;
1508
1810
  oid_text = NULL;
1509
1811
  private_key = NULL;
1510
1812
  ret = PQ_SUCCESS;
@@ -1513,7 +1815,7 @@ cleanup:
1513
1815
  if (oid_text)
1514
1816
  free(oid_text);
1515
1817
  if (private_key) {
1516
- pq_secure_wipe(private_key, priv_len);
1818
+ pq_secure_wipe(private_key, parts.private_key_len);
1517
1819
  free(private_key);
1518
1820
  }
1519
1821
  return ret;
@@ -1523,14 +1825,10 @@ int pq_pkcs8_encrypt_private_key_info_der(uint8_t **output, size_t *output_len,
1523
1825
  const uint8_t *plain_der, size_t plain_der_len,
1524
1826
  const char *passphrase, size_t passphrase_len,
1525
1827
  int iterations) {
1526
- const unsigned char *cursor;
1527
- PKCS8_PRIV_KEY_INFO *p8 = NULL;
1528
1828
  X509_SIG *encrypted = NULL;
1529
- unsigned char salt[16];
1530
1829
  unsigned char *der = NULL;
1531
- unsigned char *der_cursor;
1532
- int der_len;
1533
- int ret = PQ_ERROR_OPENSSL;
1830
+ size_t der_len = 0;
1831
+ int ret;
1534
1832
 
1535
1833
  if (!output || !output_len || !plain_der || !passphrase || iterations <= 0 ||
1536
1834
  passphrase_len > (size_t)INT_MAX || plain_der_len > (size_t)LONG_MAX)
@@ -1538,61 +1836,36 @@ int pq_pkcs8_encrypt_private_key_info_der(uint8_t **output, size_t *output_len,
1538
1836
  *output = NULL;
1539
1837
  *output_len = 0;
1540
1838
 
1541
- cursor = plain_der;
1542
- p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &cursor, (long)plain_der_len);
1543
- if (!p8 || cursor != plain_der + plain_der_len)
1544
- goto cleanup;
1545
- if (RAND_bytes(salt, sizeof(salt)) != 1)
1546
- goto cleanup;
1547
-
1548
- encrypted = PKCS8_encrypt(-1, EVP_aes_256_cbc(), passphrase, (int)passphrase_len, salt,
1549
- (int)sizeof(salt), iterations, p8);
1550
- if (!encrypted)
1551
- goto cleanup;
1552
-
1553
- der_len = i2d_X509_SIG(encrypted, NULL);
1554
- if (der_len <= 0) {
1555
- ret = PQ_ERROR_OPENSSL;
1556
- goto cleanup;
1557
- }
1558
- der = malloc((size_t)der_len);
1559
- if (!der) {
1560
- ret = PQ_ERROR_NOMEM;
1839
+ ret = pq_pkcs8_encrypt(plain_der, plain_der_len, passphrase, passphrase_len, iterations,
1840
+ &encrypted);
1841
+ if (ret != PQ_SUCCESS)
1561
1842
  goto cleanup;
1562
- }
1563
- der_cursor = der;
1564
- if (i2d_X509_SIG(encrypted, &der_cursor) != der_len ||
1565
- (size_t)(der_cursor - der) != (size_t)der_len)
1843
+ ret = pq_x509_sig_to_der(encrypted, &der, &der_len);
1844
+ if (ret != PQ_SUCCESS)
1566
1845
  goto cleanup;
1567
1846
 
1568
1847
  *output = der;
1569
- *output_len = (size_t)der_len;
1848
+ *output_len = der_len;
1570
1849
  der = NULL;
1571
1850
  ret = PQ_SUCCESS;
1572
1851
 
1573
1852
  cleanup:
1574
- pq_secure_wipe(salt, sizeof(salt));
1575
1853
  if (der) {
1576
- pq_secure_wipe(der, (size_t)(der_len > 0 ? der_len : 0));
1854
+ pq_secure_wipe(der, der_len);
1577
1855
  free(der);
1578
1856
  }
1579
1857
  if (encrypted)
1580
1858
  X509_SIG_free(encrypted);
1581
- if (p8)
1582
- PKCS8_PRIV_KEY_INFO_free(p8);
1583
1859
  return ret;
1584
1860
  }
1585
1861
 
1586
1862
  int pq_pkcs8_decrypt_private_key_info_der(uint8_t **output, size_t *output_len,
1587
1863
  const uint8_t *encrypted_der, size_t encrypted_der_len,
1588
1864
  const char *passphrase, size_t passphrase_len) {
1589
- const unsigned char *cursor;
1590
- X509_SIG *encrypted = NULL;
1591
1865
  PKCS8_PRIV_KEY_INFO *p8 = NULL;
1592
1866
  unsigned char *der = NULL;
1593
- unsigned char *der_cursor;
1594
- int der_len;
1595
- int ret = PQ_ERROR_OPENSSL;
1867
+ size_t der_len = 0;
1868
+ int ret;
1596
1869
 
1597
1870
  if (!output || !output_len || !encrypted_der || !passphrase ||
1598
1871
  passphrase_len > (size_t)INT_MAX || encrypted_der_len > (size_t)LONG_MAX)
@@ -1600,41 +1873,25 @@ int pq_pkcs8_decrypt_private_key_info_der(uint8_t **output, size_t *output_len,
1600
1873
  *output = NULL;
1601
1874
  *output_len = 0;
1602
1875
 
1603
- cursor = encrypted_der;
1604
- encrypted = d2i_X509_SIG(NULL, &cursor, (long)encrypted_der_len);
1605
- if (!encrypted || cursor != encrypted_der + encrypted_der_len)
1606
- goto cleanup;
1607
- p8 = PKCS8_decrypt(encrypted, passphrase, (int)passphrase_len);
1608
- if (!p8)
1609
- goto cleanup;
1610
-
1611
- der_len = i2d_PKCS8_PRIV_KEY_INFO(p8, NULL);
1612
- if (der_len <= 0)
1613
- goto cleanup;
1614
- der = malloc((size_t)der_len);
1615
- if (!der) {
1616
- ret = PQ_ERROR_NOMEM;
1876
+ ret = pq_pkcs8_decrypt(encrypted_der, encrypted_der_len, passphrase, passphrase_len, &p8);
1877
+ if (ret != PQ_SUCCESS)
1617
1878
  goto cleanup;
1618
- }
1619
- der_cursor = der;
1620
- if (i2d_PKCS8_PRIV_KEY_INFO(p8, &der_cursor) != der_len ||
1621
- (size_t)(der_cursor - der) != (size_t)der_len)
1879
+ ret = pq_pkcs8_info_to_der(p8, &der, &der_len);
1880
+ if (ret != PQ_SUCCESS)
1622
1881
  goto cleanup;
1623
1882
 
1624
1883
  *output = der;
1625
- *output_len = (size_t)der_len;
1884
+ *output_len = der_len;
1626
1885
  der = NULL;
1627
1886
  ret = PQ_SUCCESS;
1628
1887
 
1629
1888
  cleanup:
1630
1889
  if (der) {
1631
- pq_secure_wipe(der, (size_t)(der_len > 0 ? der_len : 0));
1890
+ pq_secure_wipe(der, der_len);
1632
1891
  free(der);
1633
1892
  }
1634
1893
  if (p8)
1635
1894
  PKCS8_PRIV_KEY_INFO_free(p8);
1636
- if (encrypted)
1637
- X509_SIG_free(encrypted);
1638
1895
  return ret;
1639
1896
  }
1640
1897