pq_crypto 0.6.7 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/ext/pqcrypto/pqcrypto_ruby_secure.c +41 -11
- data/ext/pqcrypto/pqcrypto_secure.c +501 -296
- data/ext/pqcrypto/pqcrypto_version.h +1 -1
- data/lib/pq_crypto/internal.rb +10 -0
- data/lib/pq_crypto/kem.rb +5 -10
- data/lib/pq_crypto/pkcs8/der.rb +26 -11
- data/lib/pq_crypto/pkcs8/private_key_choice.rb +21 -25
- data/lib/pq_crypto/signature.rb +28 -40
- data/lib/pq_crypto/spki.rb +36 -23
- data/lib/pq_crypto/version.rb +1 -1
- metadata +1 -1
|
@@ -783,13 +783,46 @@ static const pq_serialization_algorithm_t *pq_find_serialization_algorithm_by_oi
|
|
|
783
783
|
return NULL;
|
|
784
784
|
}
|
|
785
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
|
+
|
|
786
819
|
static int pq_encode_serialized_key(uint8_t **output, size_t *output_len, uint8_t type,
|
|
787
820
|
const uint8_t *key_bytes, size_t key_len,
|
|
788
821
|
const char *algorithm) {
|
|
789
822
|
const pq_serialization_algorithm_t *entry;
|
|
790
823
|
size_t expected_len;
|
|
791
824
|
size_t oid_len;
|
|
792
|
-
size_t total_len
|
|
825
|
+
size_t total_len;
|
|
793
826
|
uint8_t *buf;
|
|
794
827
|
int ret;
|
|
795
828
|
|
|
@@ -814,19 +847,7 @@ static int pq_encode_serialized_key(uint8_t **output, size_t *output_len, uint8_
|
|
|
814
847
|
if (key_len > UINT32_MAX)
|
|
815
848
|
return PQ_ERROR_BUFFER;
|
|
816
849
|
|
|
817
|
-
ret =
|
|
818
|
-
if (ret != PQ_SUCCESS)
|
|
819
|
-
return ret;
|
|
820
|
-
ret = pq_size_add(total_len, 1 + 1 + 2, &total_len);
|
|
821
|
-
if (ret != PQ_SUCCESS)
|
|
822
|
-
return ret;
|
|
823
|
-
ret = pq_size_add(total_len, oid_len, &total_len);
|
|
824
|
-
if (ret != PQ_SUCCESS)
|
|
825
|
-
return ret;
|
|
826
|
-
ret = pq_size_add(total_len, 4, &total_len);
|
|
827
|
-
if (ret != PQ_SUCCESS)
|
|
828
|
-
return ret;
|
|
829
|
-
ret = pq_size_add(total_len, key_len, &total_len);
|
|
850
|
+
ret = pq_serialized_key_size(oid_len, key_len, &total_len);
|
|
830
851
|
if (ret != PQ_SUCCESS)
|
|
831
852
|
return ret;
|
|
832
853
|
|
|
@@ -840,13 +861,9 @@ static int pq_encode_serialized_key(uint8_t **output, size_t *output_len, uint8_
|
|
|
840
861
|
buf[3] = PQC_SERIALIZATION_MAGIC_3;
|
|
841
862
|
buf[4] = PQC_SERIALIZATION_VERSION;
|
|
842
863
|
buf[5] = type;
|
|
843
|
-
buf
|
|
844
|
-
buf[7] = (uint8_t)(oid_len & 0xFF);
|
|
864
|
+
pq_write_u16be(buf + 6, (uint16_t)oid_len);
|
|
845
865
|
memcpy(buf + 8, entry->oid, oid_len);
|
|
846
|
-
buf
|
|
847
|
-
buf[8 + oid_len + 1] = (uint8_t)((key_len >> 16) & 0xFF);
|
|
848
|
-
buf[8 + oid_len + 2] = (uint8_t)((key_len >> 8) & 0xFF);
|
|
849
|
-
buf[8 + oid_len + 3] = (uint8_t)(key_len & 0xFF);
|
|
866
|
+
pq_write_u32be(buf + 8 + oid_len, (uint32_t)key_len);
|
|
850
867
|
memcpy(buf + 8 + oid_len + 4, key_bytes, key_len);
|
|
851
868
|
|
|
852
869
|
*output = buf;
|
|
@@ -854,62 +871,92 @@ static int pq_encode_serialized_key(uint8_t **output, size_t *output_len, uint8_
|
|
|
854
871
|
return PQ_SUCCESS;
|
|
855
872
|
}
|
|
856
873
|
|
|
857
|
-
static int
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
uint32_t key_len;
|
|
861
|
-
const pq_serialization_algorithm_t *entry;
|
|
862
|
-
size_t offset;
|
|
863
|
-
size_t expected_len = 0;
|
|
864
|
-
uint8_t *key_copy = NULL;
|
|
865
|
-
char *algorithm_copy = NULL;
|
|
866
|
-
|
|
867
|
-
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)
|
|
868
877
|
return PQ_ERROR_BUFFER;
|
|
869
|
-
|
|
870
|
-
*algorithm_out = NULL;
|
|
871
|
-
*key_out = NULL;
|
|
872
|
-
*key_len_out = 0;
|
|
873
|
-
|
|
874
878
|
if (input_len < 12)
|
|
875
879
|
return PQ_ERROR_BUFFER;
|
|
876
880
|
if (input[0] != PQC_SERIALIZATION_MAGIC_0 || input[1] != PQC_SERIALIZATION_MAGIC_1 ||
|
|
877
|
-
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)
|
|
878
882
|
return PQ_ERROR_BUFFER;
|
|
879
|
-
}
|
|
880
883
|
if (input[4] != PQC_SERIALIZATION_VERSION || input[5] != expected_type)
|
|
881
884
|
return PQ_ERROR_BUFFER;
|
|
882
885
|
|
|
883
|
-
|
|
884
|
-
if (
|
|
886
|
+
*oid_len_out = pq_read_u16be(input + 6);
|
|
887
|
+
if (*oid_len_out == 0 || input_len - 8 < (size_t)*oid_len_out + 4)
|
|
885
888
|
return PQ_ERROR_BUFFER;
|
|
886
|
-
|
|
887
|
-
|
|
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)
|
|
888
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;
|
|
889
911
|
entry = pq_find_serialization_algorithm_by_oid((const char *)(input + offset), oid_len);
|
|
890
912
|
if (!entry)
|
|
891
913
|
return PQ_ERROR_BUFFER;
|
|
892
914
|
offset += oid_len;
|
|
893
|
-
key_len = (
|
|
894
|
-
((uint32_t)input[offset + 2] << 8) | (uint32_t)input[offset + 3];
|
|
915
|
+
key_len = pq_read_u32be(input + offset);
|
|
895
916
|
offset += 4;
|
|
896
|
-
if (input_len
|
|
917
|
+
if (input_len - offset != (size_t)key_len)
|
|
897
918
|
return PQ_ERROR_BUFFER;
|
|
898
919
|
expected_len = (expected_type == PQC_SERIALIZATION_TYPE_PUBLIC) ? entry->public_key_len
|
|
899
920
|
: entry->secret_key_len;
|
|
900
921
|
if ((size_t)key_len != expected_len)
|
|
901
922
|
return PQ_ERROR_BUFFER;
|
|
902
923
|
|
|
903
|
-
|
|
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);
|
|
904
951
|
if (!key_copy)
|
|
905
952
|
return PQ_ERROR_NOMEM;
|
|
906
|
-
memcpy(key_copy,
|
|
953
|
+
memcpy(key_copy, key_data, key_len);
|
|
907
954
|
|
|
908
955
|
{
|
|
909
956
|
size_t algorithm_len = strlen(entry->algorithm);
|
|
910
957
|
algorithm_copy = malloc(algorithm_len + 1);
|
|
911
958
|
if (!algorithm_copy) {
|
|
912
|
-
pq_secure_wipe(key_copy,
|
|
959
|
+
pq_secure_wipe(key_copy, key_len);
|
|
913
960
|
free(key_copy);
|
|
914
961
|
return PQ_ERROR_NOMEM;
|
|
915
962
|
}
|
|
@@ -918,7 +965,7 @@ static int pq_decode_serialized_key(const uint8_t *input, size_t input_len, uint
|
|
|
918
965
|
|
|
919
966
|
*algorithm_out = algorithm_copy;
|
|
920
967
|
*key_out = key_copy;
|
|
921
|
-
*key_len_out =
|
|
968
|
+
*key_len_out = key_len;
|
|
922
969
|
return PQ_SUCCESS;
|
|
923
970
|
}
|
|
924
971
|
|
|
@@ -950,6 +997,143 @@ static const char *pq_find_pem_footer(const char *start, size_t len, const char
|
|
|
950
997
|
return NULL;
|
|
951
998
|
}
|
|
952
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
|
+
|
|
953
1137
|
static int pq_der_to_pem(const char *label, const uint8_t *der, size_t der_len, char **output,
|
|
954
1138
|
size_t *output_len) {
|
|
955
1139
|
char header[64];
|
|
@@ -960,7 +1144,7 @@ static int pq_der_to_pem(const char *label, const uint8_t *der, size_t der_len,
|
|
|
960
1144
|
size_t encoded_len;
|
|
961
1145
|
size_t line_count;
|
|
962
1146
|
size_t needed;
|
|
963
|
-
|
|
1147
|
+
int ret;
|
|
964
1148
|
|
|
965
1149
|
if (!label || !der || !output || !output_len)
|
|
966
1150
|
return PQ_ERROR_BUFFER;
|
|
@@ -971,32 +1155,18 @@ static int pq_der_to_pem(const char *label, const uint8_t *der, size_t der_len,
|
|
|
971
1155
|
footer_len = snprintf(footer, sizeof(footer), "-----END %s-----", label);
|
|
972
1156
|
if (header_len <= 0 || footer_len <= 0)
|
|
973
1157
|
return PQ_ERROR_BUFFER;
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
encoded_len = 4 * ((der_len + 2) / 3);
|
|
978
|
-
if (encoded_len > (size_t)INT_MAX)
|
|
979
|
-
return PQ_ERROR_BUFFER;
|
|
980
|
-
|
|
981
|
-
encoded = malloc(encoded_len + 1);
|
|
982
|
-
if (!encoded)
|
|
983
|
-
return PQ_ERROR_NOMEM;
|
|
984
|
-
|
|
985
|
-
if (EVP_EncodeBlock(encoded, der, (int)der_len) != (int)encoded_len) {
|
|
986
|
-
pq_secure_wipe(encoded, encoded_len + 1);
|
|
987
|
-
free(encoded);
|
|
988
|
-
return PQ_ERROR_OPENSSL;
|
|
989
|
-
}
|
|
1158
|
+
ret = pq_base64_encode_der(der, der_len, &encoded, &encoded_len);
|
|
1159
|
+
if (ret != PQ_SUCCESS)
|
|
1160
|
+
return ret;
|
|
990
1161
|
|
|
991
1162
|
line_count = encoded_len == 0 ? 0 : ((encoded_len + 63) / 64);
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
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) {
|
|
995
1166
|
pq_secure_wipe(encoded, encoded_len + 1);
|
|
996
1167
|
free(encoded);
|
|
997
|
-
return
|
|
1168
|
+
return ret;
|
|
998
1169
|
}
|
|
999
|
-
needed = (size_t)header_len + 1 + encoded_len + line_count + (size_t)footer_len + 1;
|
|
1000
1170
|
|
|
1001
1171
|
pem = malloc(needed);
|
|
1002
1172
|
if (!pem) {
|
|
@@ -1005,26 +1175,9 @@ static int pq_der_to_pem(const char *label, const uint8_t *der, size_t der_len,
|
|
|
1005
1175
|
return PQ_ERROR_NOMEM;
|
|
1006
1176
|
}
|
|
1007
1177
|
|
|
1008
|
-
cur = pem;
|
|
1009
|
-
memcpy(cur, header, (size_t)header_len);
|
|
1010
|
-
cur += header_len;
|
|
1011
|
-
*cur++ = '\n';
|
|
1012
|
-
|
|
1013
|
-
for (size_t offset = 0; offset < encoded_len; offset += 64) {
|
|
1014
|
-
size_t line_len = encoded_len - offset;
|
|
1015
|
-
if (line_len > 64)
|
|
1016
|
-
line_len = 64;
|
|
1017
|
-
memcpy(cur, encoded + offset, line_len);
|
|
1018
|
-
cur += line_len;
|
|
1019
|
-
*cur++ = '\n';
|
|
1020
|
-
}
|
|
1021
|
-
|
|
1022
|
-
memcpy(cur, footer, (size_t)footer_len);
|
|
1023
|
-
cur += footer_len;
|
|
1024
|
-
*cur = '\0';
|
|
1025
|
-
|
|
1026
1178
|
*output = pem;
|
|
1027
|
-
*output_len = (size_t)
|
|
1179
|
+
*output_len = pq_write_pem_body(pem, header, (size_t)header_len, encoded, encoded_len, footer,
|
|
1180
|
+
(size_t)footer_len);
|
|
1028
1181
|
pq_secure_wipe(encoded, encoded_len + 1);
|
|
1029
1182
|
free(encoded);
|
|
1030
1183
|
return PQ_SUCCESS;
|
|
@@ -1032,10 +1185,7 @@ static int pq_der_to_pem(const char *label, const uint8_t *der, size_t der_len,
|
|
|
1032
1185
|
|
|
1033
1186
|
static int pq_pem_to_der(const char *label, const char *input, size_t input_len, uint8_t **der_out,
|
|
1034
1187
|
size_t *der_len_out) {
|
|
1035
|
-
char
|
|
1036
|
-
int header_len, footer_len;
|
|
1037
|
-
const char *body_start, *footer_pos;
|
|
1038
|
-
const char *tail;
|
|
1188
|
+
const char *body_start;
|
|
1039
1189
|
uint8_t *der = NULL;
|
|
1040
1190
|
unsigned char *compact = NULL;
|
|
1041
1191
|
size_t body_len = 0;
|
|
@@ -1043,79 +1193,21 @@ static int pq_pem_to_der(const char *label, const char *input, size_t input_len,
|
|
|
1043
1193
|
size_t der_cap = 0;
|
|
1044
1194
|
int decoded_len = 0;
|
|
1045
1195
|
int padding = 0;
|
|
1046
|
-
int
|
|
1196
|
+
int ret;
|
|
1047
1197
|
|
|
1048
1198
|
if (!label || !input || !der_out || !der_len_out)
|
|
1049
1199
|
return PQ_ERROR_BUFFER;
|
|
1050
1200
|
*der_out = NULL;
|
|
1051
1201
|
*der_len_out = 0;
|
|
1052
1202
|
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
if (
|
|
1058
|
-
return
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
body_start = input + header_len;
|
|
1063
|
-
while ((size_t)(body_start - input) < input_len && pq_is_pem_whitespace(*body_start))
|
|
1064
|
-
body_start++;
|
|
1065
|
-
|
|
1066
|
-
footer_pos = pq_find_pem_footer(body_start, input_len - (size_t)(body_start - input), footer,
|
|
1067
|
-
(size_t)footer_len);
|
|
1068
|
-
if (!footer_pos)
|
|
1069
|
-
return PQ_ERROR_BUFFER;
|
|
1070
|
-
|
|
1071
|
-
tail = footer_pos + footer_len;
|
|
1072
|
-
while ((size_t)(tail - input) < input_len) {
|
|
1073
|
-
if (!pq_is_pem_whitespace(*tail))
|
|
1074
|
-
return PQ_ERROR_BUFFER;
|
|
1075
|
-
tail++;
|
|
1076
|
-
}
|
|
1077
|
-
|
|
1078
|
-
body_len = (size_t)(footer_pos - body_start);
|
|
1079
|
-
if (body_len > (size_t)INT_MAX)
|
|
1080
|
-
return PQ_ERROR_BUFFER;
|
|
1081
|
-
|
|
1082
|
-
compact = malloc(body_len ? body_len : 1);
|
|
1083
|
-
if (!compact)
|
|
1084
|
-
return PQ_ERROR_NOMEM;
|
|
1085
|
-
|
|
1086
|
-
for (size_t i = 0; i < body_len; ++i) {
|
|
1087
|
-
unsigned char c = (unsigned char)body_start[i];
|
|
1088
|
-
int value;
|
|
1089
|
-
if (pq_is_pem_whitespace((char)c))
|
|
1090
|
-
continue;
|
|
1091
|
-
|
|
1092
|
-
value = pq_base64_char_value(c);
|
|
1093
|
-
if (value < 0) {
|
|
1094
|
-
pq_secure_wipe(compact, body_len);
|
|
1095
|
-
free(compact);
|
|
1096
|
-
return PQ_ERROR_BUFFER;
|
|
1097
|
-
}
|
|
1098
|
-
if (c == '=') {
|
|
1099
|
-
saw_padding = 1;
|
|
1100
|
-
padding++;
|
|
1101
|
-
if (padding > 2) {
|
|
1102
|
-
pq_secure_wipe(compact, body_len);
|
|
1103
|
-
free(compact);
|
|
1104
|
-
return PQ_ERROR_BUFFER;
|
|
1105
|
-
}
|
|
1106
|
-
} else if (saw_padding) {
|
|
1107
|
-
pq_secure_wipe(compact, body_len);
|
|
1108
|
-
free(compact);
|
|
1109
|
-
return PQ_ERROR_BUFFER;
|
|
1110
|
-
}
|
|
1111
|
-
compact[compact_len++] = c;
|
|
1112
|
-
}
|
|
1113
|
-
|
|
1114
|
-
if (compact_len == 0 || (compact_len % 4) != 0 || compact_len > (size_t)INT_MAX) {
|
|
1115
|
-
pq_secure_wipe(compact, body_len);
|
|
1116
|
-
free(compact);
|
|
1117
|
-
return PQ_ERROR_BUFFER;
|
|
1118
|
-
}
|
|
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++;
|
|
1119
1211
|
|
|
1120
1212
|
der_cap = (compact_len / 4) * 3;
|
|
1121
1213
|
der = malloc(der_cap ? der_cap : 1);
|
|
@@ -1408,11 +1500,224 @@ cleanup:
|
|
|
1408
1500
|
return ret;
|
|
1409
1501
|
}
|
|
1410
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
|
+
|
|
1411
1716
|
int pq_pkcs8_private_key_info_to_der(uint8_t **output, size_t *output_len, const char *oid_text,
|
|
1412
1717
|
const uint8_t *private_key, size_t private_key_len) {
|
|
1413
1718
|
uint8_t *oid_der = NULL;
|
|
1414
1719
|
size_t oid_der_len = 0;
|
|
1415
|
-
|
|
1720
|
+
pq_pkcs8_size_t der_size = {0};
|
|
1416
1721
|
uint8_t *buf = NULL;
|
|
1417
1722
|
uint8_t *cur;
|
|
1418
1723
|
int ret;
|
|
@@ -1426,58 +1731,42 @@ int pq_pkcs8_private_key_info_to_der(uint8_t **output, size_t *output_len, const
|
|
|
1426
1731
|
if (ret != PQ_SUCCESS)
|
|
1427
1732
|
return ret;
|
|
1428
1733
|
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
priv_len = 1 + pq_der_length_octets(private_key_len) + private_key_len;
|
|
1432
|
-
if (pq_size_add(3, alg_len, &inner_len) != PQ_SUCCESS ||
|
|
1433
|
-
pq_size_add(inner_len, priv_len, &inner_len) != PQ_SUCCESS) {
|
|
1434
|
-
ret = PQ_ERROR_BUFFER;
|
|
1435
|
-
goto cleanup;
|
|
1436
|
-
}
|
|
1437
|
-
if (pq_size_add(1 + pq_der_length_octets(inner_len), inner_len, &total_len) != PQ_SUCCESS) {
|
|
1438
|
-
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)
|
|
1439
1736
|
goto cleanup;
|
|
1440
|
-
}
|
|
1441
1737
|
|
|
1442
|
-
buf = malloc(total_len);
|
|
1738
|
+
buf = malloc(der_size.total_len);
|
|
1443
1739
|
if (!buf) {
|
|
1444
1740
|
ret = PQ_ERROR_NOMEM;
|
|
1445
1741
|
goto cleanup;
|
|
1446
1742
|
}
|
|
1447
1743
|
|
|
1448
1744
|
cur = buf;
|
|
1449
|
-
|
|
1450
|
-
ret = pq_der_write_length(&cur, inner_len);
|
|
1745
|
+
ret = pq_der_write_tlv_header(0x30, &cur, der_size.inner_len);
|
|
1451
1746
|
if (ret != PQ_SUCCESS)
|
|
1452
1747
|
goto cleanup;
|
|
1453
1748
|
*cur++ = 0x02;
|
|
1454
1749
|
*cur++ = 0x01;
|
|
1455
1750
|
*cur++ = 0x00;
|
|
1456
|
-
|
|
1457
|
-
ret = pq_der_write_length(&cur, alg_body_len);
|
|
1751
|
+
ret = pq_der_write_tlv(&cur, 0x30, oid_der, oid_der_len);
|
|
1458
1752
|
if (ret != PQ_SUCCESS)
|
|
1459
1753
|
goto cleanup;
|
|
1460
|
-
|
|
1461
|
-
cur += oid_der_len;
|
|
1462
|
-
*cur++ = 0x04;
|
|
1463
|
-
ret = pq_der_write_length(&cur, private_key_len);
|
|
1754
|
+
ret = pq_der_write_tlv(&cur, 0x04, private_key, private_key_len);
|
|
1464
1755
|
if (ret != PQ_SUCCESS)
|
|
1465
1756
|
goto cleanup;
|
|
1466
|
-
|
|
1467
|
-
cur += private_key_len;
|
|
1468
|
-
if ((size_t)(cur - buf) != total_len) {
|
|
1757
|
+
if ((size_t)(cur - buf) != der_size.total_len) {
|
|
1469
1758
|
ret = PQ_ERROR_BUFFER;
|
|
1470
1759
|
goto cleanup;
|
|
1471
1760
|
}
|
|
1472
1761
|
|
|
1473
1762
|
*output = buf;
|
|
1474
|
-
*output_len = total_len;
|
|
1763
|
+
*output_len = der_size.total_len;
|
|
1475
1764
|
buf = NULL;
|
|
1476
1765
|
ret = PQ_SUCCESS;
|
|
1477
1766
|
|
|
1478
1767
|
cleanup:
|
|
1479
1768
|
if (buf) {
|
|
1480
|
-
pq_secure_wipe(buf, total_len);
|
|
1769
|
+
pq_secure_wipe(buf, der_size.total_len);
|
|
1481
1770
|
free(buf);
|
|
1482
1771
|
}
|
|
1483
1772
|
if (oid_der) {
|
|
@@ -1490,11 +1779,7 @@ cleanup:
|
|
|
1490
1779
|
int pq_pkcs8_private_key_info_from_der(char **oid_text_out, uint8_t **private_key_out,
|
|
1491
1780
|
size_t *private_key_len_out, const uint8_t *input,
|
|
1492
1781
|
size_t input_len) {
|
|
1493
|
-
|
|
1494
|
-
size_t outer_off = 0, outer_len = 0, outer_end;
|
|
1495
|
-
size_t alg_off = 0, alg_len = 0, alg_end;
|
|
1496
|
-
size_t oid_off = 0, oid_len = 0;
|
|
1497
|
-
size_t priv_off = 0, priv_len = 0;
|
|
1782
|
+
pq_pkcs8_parts_t parts = {0};
|
|
1498
1783
|
uint8_t *private_key = NULL;
|
|
1499
1784
|
char *oid_text = NULL;
|
|
1500
1785
|
int ret;
|
|
@@ -1505,58 +1790,23 @@ int pq_pkcs8_private_key_info_from_der(char **oid_text_out, uint8_t **private_ke
|
|
|
1505
1790
|
*private_key_out = NULL;
|
|
1506
1791
|
*private_key_len_out = 0;
|
|
1507
1792
|
|
|
1508
|
-
ret =
|
|
1793
|
+
ret = pq_pkcs8_parse_parts(input, input_len, &parts);
|
|
1509
1794
|
if (ret != PQ_SUCCESS)
|
|
1510
1795
|
return ret;
|
|
1511
|
-
|
|
1512
|
-
if (offset != input_len || outer_end != input_len)
|
|
1513
|
-
return PQ_ERROR_BUFFER;
|
|
1514
|
-
|
|
1515
|
-
offset = outer_off;
|
|
1516
|
-
{
|
|
1517
|
-
size_t version_off = 0, version_len = 0;
|
|
1518
|
-
ret = pq_der_expect_tlv(input, outer_end, &offset, 0x02, &version_off, &version_len);
|
|
1519
|
-
if (ret != PQ_SUCCESS)
|
|
1520
|
-
return ret;
|
|
1521
|
-
if (version_len != 1 || input[version_off] != 0x00)
|
|
1522
|
-
return PQ_ERROR_BUFFER;
|
|
1523
|
-
}
|
|
1524
|
-
|
|
1525
|
-
ret = pq_der_expect_tlv(input, outer_end, &offset, 0x30, &alg_off, &alg_len);
|
|
1796
|
+
ret = pq_oid_der_to_text(input + parts.oid_offset, parts.oid_tlv_len, &oid_text);
|
|
1526
1797
|
if (ret != PQ_SUCCESS)
|
|
1527
1798
|
return ret;
|
|
1528
|
-
|
|
1529
|
-
{
|
|
1530
|
-
size_t alg_cursor = alg_off;
|
|
1531
|
-
size_t oid_tlv_start = alg_cursor;
|
|
1532
|
-
ret = pq_der_expect_tlv(input, alg_end, &alg_cursor, 0x06, &oid_off, &oid_len);
|
|
1533
|
-
if (ret != PQ_SUCCESS)
|
|
1534
|
-
return ret;
|
|
1535
|
-
if (alg_cursor != alg_end)
|
|
1536
|
-
return PQ_ERROR_BUFFER;
|
|
1537
|
-
ret = pq_oid_der_to_text(input + oid_tlv_start, alg_cursor - oid_tlv_start, &oid_text);
|
|
1538
|
-
}
|
|
1539
|
-
if (ret != PQ_SUCCESS)
|
|
1540
|
-
return ret;
|
|
1541
|
-
|
|
1542
|
-
ret = pq_der_expect_tlv(input, outer_end, &offset, 0x04, &priv_off, &priv_len);
|
|
1543
|
-
if (ret != PQ_SUCCESS)
|
|
1544
|
-
goto cleanup;
|
|
1545
|
-
if (offset != outer_end) {
|
|
1546
|
-
ret = PQ_ERROR_BUFFER;
|
|
1547
|
-
goto cleanup;
|
|
1548
|
-
}
|
|
1549
|
-
private_key = malloc(priv_len ? priv_len : 1);
|
|
1799
|
+
private_key = malloc(parts.private_key_len ? parts.private_key_len : 1);
|
|
1550
1800
|
if (!private_key) {
|
|
1551
1801
|
ret = PQ_ERROR_NOMEM;
|
|
1552
1802
|
goto cleanup;
|
|
1553
1803
|
}
|
|
1554
|
-
if (
|
|
1555
|
-
memcpy(private_key, input +
|
|
1804
|
+
if (parts.private_key_len)
|
|
1805
|
+
memcpy(private_key, input + parts.private_key_offset, parts.private_key_len);
|
|
1556
1806
|
|
|
1557
1807
|
*oid_text_out = oid_text;
|
|
1558
1808
|
*private_key_out = private_key;
|
|
1559
|
-
*private_key_len_out =
|
|
1809
|
+
*private_key_len_out = parts.private_key_len;
|
|
1560
1810
|
oid_text = NULL;
|
|
1561
1811
|
private_key = NULL;
|
|
1562
1812
|
ret = PQ_SUCCESS;
|
|
@@ -1565,7 +1815,7 @@ cleanup:
|
|
|
1565
1815
|
if (oid_text)
|
|
1566
1816
|
free(oid_text);
|
|
1567
1817
|
if (private_key) {
|
|
1568
|
-
pq_secure_wipe(private_key,
|
|
1818
|
+
pq_secure_wipe(private_key, parts.private_key_len);
|
|
1569
1819
|
free(private_key);
|
|
1570
1820
|
}
|
|
1571
1821
|
return ret;
|
|
@@ -1575,14 +1825,10 @@ int pq_pkcs8_encrypt_private_key_info_der(uint8_t **output, size_t *output_len,
|
|
|
1575
1825
|
const uint8_t *plain_der, size_t plain_der_len,
|
|
1576
1826
|
const char *passphrase, size_t passphrase_len,
|
|
1577
1827
|
int iterations) {
|
|
1578
|
-
const unsigned char *cursor;
|
|
1579
|
-
PKCS8_PRIV_KEY_INFO *p8 = NULL;
|
|
1580
1828
|
X509_SIG *encrypted = NULL;
|
|
1581
|
-
unsigned char salt[16];
|
|
1582
1829
|
unsigned char *der = NULL;
|
|
1583
|
-
|
|
1584
|
-
int
|
|
1585
|
-
int ret = PQ_ERROR_OPENSSL;
|
|
1830
|
+
size_t der_len = 0;
|
|
1831
|
+
int ret;
|
|
1586
1832
|
|
|
1587
1833
|
if (!output || !output_len || !plain_der || !passphrase || iterations <= 0 ||
|
|
1588
1834
|
passphrase_len > (size_t)INT_MAX || plain_der_len > (size_t)LONG_MAX)
|
|
@@ -1590,61 +1836,36 @@ int pq_pkcs8_encrypt_private_key_info_der(uint8_t **output, size_t *output_len,
|
|
|
1590
1836
|
*output = NULL;
|
|
1591
1837
|
*output_len = 0;
|
|
1592
1838
|
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
if (
|
|
1596
|
-
goto cleanup;
|
|
1597
|
-
if (RAND_bytes(salt, sizeof(salt)) != 1)
|
|
1598
|
-
goto cleanup;
|
|
1599
|
-
|
|
1600
|
-
encrypted = PKCS8_encrypt(-1, EVP_aes_256_cbc(), passphrase, (int)passphrase_len, salt,
|
|
1601
|
-
(int)sizeof(salt), iterations, p8);
|
|
1602
|
-
if (!encrypted)
|
|
1603
|
-
goto cleanup;
|
|
1604
|
-
|
|
1605
|
-
der_len = i2d_X509_SIG(encrypted, NULL);
|
|
1606
|
-
if (der_len <= 0) {
|
|
1607
|
-
ret = PQ_ERROR_OPENSSL;
|
|
1608
|
-
goto cleanup;
|
|
1609
|
-
}
|
|
1610
|
-
der = malloc((size_t)der_len);
|
|
1611
|
-
if (!der) {
|
|
1612
|
-
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)
|
|
1613
1842
|
goto cleanup;
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
if (i2d_X509_SIG(encrypted, &der_cursor) != der_len ||
|
|
1617
|
-
(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)
|
|
1618
1845
|
goto cleanup;
|
|
1619
1846
|
|
|
1620
1847
|
*output = der;
|
|
1621
|
-
*output_len =
|
|
1848
|
+
*output_len = der_len;
|
|
1622
1849
|
der = NULL;
|
|
1623
1850
|
ret = PQ_SUCCESS;
|
|
1624
1851
|
|
|
1625
1852
|
cleanup:
|
|
1626
|
-
pq_secure_wipe(salt, sizeof(salt));
|
|
1627
1853
|
if (der) {
|
|
1628
|
-
pq_secure_wipe(der,
|
|
1854
|
+
pq_secure_wipe(der, der_len);
|
|
1629
1855
|
free(der);
|
|
1630
1856
|
}
|
|
1631
1857
|
if (encrypted)
|
|
1632
1858
|
X509_SIG_free(encrypted);
|
|
1633
|
-
if (p8)
|
|
1634
|
-
PKCS8_PRIV_KEY_INFO_free(p8);
|
|
1635
1859
|
return ret;
|
|
1636
1860
|
}
|
|
1637
1861
|
|
|
1638
1862
|
int pq_pkcs8_decrypt_private_key_info_der(uint8_t **output, size_t *output_len,
|
|
1639
1863
|
const uint8_t *encrypted_der, size_t encrypted_der_len,
|
|
1640
1864
|
const char *passphrase, size_t passphrase_len) {
|
|
1641
|
-
const unsigned char *cursor;
|
|
1642
|
-
X509_SIG *encrypted = NULL;
|
|
1643
1865
|
PKCS8_PRIV_KEY_INFO *p8 = NULL;
|
|
1644
1866
|
unsigned char *der = NULL;
|
|
1645
|
-
|
|
1646
|
-
int
|
|
1647
|
-
int ret = PQ_ERROR_OPENSSL;
|
|
1867
|
+
size_t der_len = 0;
|
|
1868
|
+
int ret;
|
|
1648
1869
|
|
|
1649
1870
|
if (!output || !output_len || !encrypted_der || !passphrase ||
|
|
1650
1871
|
passphrase_len > (size_t)INT_MAX || encrypted_der_len > (size_t)LONG_MAX)
|
|
@@ -1652,41 +1873,25 @@ int pq_pkcs8_decrypt_private_key_info_der(uint8_t **output, size_t *output_len,
|
|
|
1652
1873
|
*output = NULL;
|
|
1653
1874
|
*output_len = 0;
|
|
1654
1875
|
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
if (!encrypted || cursor != encrypted_der + encrypted_der_len)
|
|
1658
|
-
goto cleanup;
|
|
1659
|
-
p8 = PKCS8_decrypt(encrypted, passphrase, (int)passphrase_len);
|
|
1660
|
-
if (!p8)
|
|
1661
|
-
goto cleanup;
|
|
1662
|
-
|
|
1663
|
-
der_len = i2d_PKCS8_PRIV_KEY_INFO(p8, NULL);
|
|
1664
|
-
if (der_len <= 0)
|
|
1665
|
-
goto cleanup;
|
|
1666
|
-
der = malloc((size_t)der_len);
|
|
1667
|
-
if (!der) {
|
|
1668
|
-
ret = PQ_ERROR_NOMEM;
|
|
1876
|
+
ret = pq_pkcs8_decrypt(encrypted_der, encrypted_der_len, passphrase, passphrase_len, &p8);
|
|
1877
|
+
if (ret != PQ_SUCCESS)
|
|
1669
1878
|
goto cleanup;
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
if (i2d_PKCS8_PRIV_KEY_INFO(p8, &der_cursor) != der_len ||
|
|
1673
|
-
(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)
|
|
1674
1881
|
goto cleanup;
|
|
1675
1882
|
|
|
1676
1883
|
*output = der;
|
|
1677
|
-
*output_len =
|
|
1884
|
+
*output_len = der_len;
|
|
1678
1885
|
der = NULL;
|
|
1679
1886
|
ret = PQ_SUCCESS;
|
|
1680
1887
|
|
|
1681
1888
|
cleanup:
|
|
1682
1889
|
if (der) {
|
|
1683
|
-
pq_secure_wipe(der,
|
|
1890
|
+
pq_secure_wipe(der, der_len);
|
|
1684
1891
|
free(der);
|
|
1685
1892
|
}
|
|
1686
1893
|
if (p8)
|
|
1687
1894
|
PKCS8_PRIV_KEY_INFO_free(p8);
|
|
1688
|
-
if (encrypted)
|
|
1689
|
-
X509_SIG_free(encrypted);
|
|
1690
1895
|
return ret;
|
|
1691
1896
|
}
|
|
1692
1897
|
|