Add ability to export ecc keys in short/oid form. (#17)
* Add PK_CURVEOID flag to ecc_export_full
The flag exports the key with it's associated ASN.1 OID which itself
references the curves parameters.
This is like OPENSSL_EC_NAMED_CURVE in OpenSSL.
* Add ecc_dp_fill_from_sets to look up missing curve parameters
Exporting with PK_CURVEOID requires knowing the OID, however only some
key formats provide the OID. ecc_dp_fill_from_sets searches our known set
of curves and fills in the missing parameters like curve OID and name.
Additional we can now make the name parameter in ecc_dp_set optional.
* Add optional OID parameter to ecc_dp_set
* Add support for PK_CURVEOID to perl-CryptX
API:
$pk->export_key_der('private_short');
$pk->export_key_der('public_short');
$pk->export_key_pem('private_short');
$pk->export_key_pem('public_short');
* Make key2hash export the OID as curve_oid
Manuel Mausz authored 7 years ago
karel-m committed 7 years ago
185 | 185 | { |
186 | 186 | HV *h; |
187 | 187 | SV *param, **pref; |
188 | SV **sv_cofactor, **sv_prime, **sv_A, **sv_B, **sv_order, **sv_Gx, **sv_Gy; | |
188 | SV **sv_cofactor, **sv_prime, **sv_A, **sv_B, **sv_order, **sv_Gx, **sv_Gy, **sv_oid; | |
189 | 189 | int err; |
190 | 190 | char *ch_name; |
191 | 191 | STRLEN l_name; |
199 | 199 | } |
200 | 200 | else if (SvROK(curve)) { |
201 | 201 | param = curve; |
202 | ch_name = "custom"; | |
203 | 202 | } |
204 | 203 | else { |
205 | 204 | croak("FATAL: curve has to be a string or a hashref"); |
231 | 230 | SvPV_nolen(*sv_Gx), |
232 | 231 | SvPV_nolen(*sv_Gy), |
233 | 232 | (unsigned long)SvUV(*sv_cofactor), |
234 | ch_name ); | |
233 | NULL, /* we intentionally don't allow setting custom names */ | |
234 | NULL /* we intentionally don't allow setting custom OIDs */ | |
235 | ); | |
235 | 236 | return err == CRYPT_OK ? dp : NULL; |
236 | 237 | } |
237 | 238 | |
427 | 428 | |
428 | 429 | INCLUDE: inc/CryptX_KeyDerivation.xs.inc |
429 | 430 | |
430 | INCLUDE: inc/CryptX_BigInt_LTM.xs.inc⏎ | |
431 | INCLUDE: inc/CryptX_BigInt_LTM.xs.inc |
168 | 168 | name = newSVpv(self->key.dp->name, strlen(self->key.dp->name)); |
169 | 169 | name_ptr = SvPV(name, name_len); |
170 | 170 | for (i=0; i<name_len && name_ptr[i]>0; i++) name_ptr[i] = toLOWER(name_ptr[i]); |
171 | not_used = hv_store(rv_hash, "curve_name", 10, name, 0); | |
171 | not_used = hv_store(rv_hash, "curve_name", 10, name, 0); | |
172 | } | |
173 | if (self->key.dp->oid.OIDlen > 0) { | |
174 | int i; | |
175 | SV *oid = newSVpv("", 0); | |
176 | for(i = 0; i < self->key.dp->oid.OIDlen - 1; i++) sv_catpvf(oid, "%lu.", self->key.dp->oid.OID[i]); | |
177 | sv_catpvf(oid, "%lu", self->key.dp->oid.OID[i]); | |
178 | not_used = hv_store(rv_hash, "curve_oid", 9, oid, 0); | |
172 | 179 | } |
173 | 180 | } |
174 | 181 | /* =====> size */ |
189 | 196 | unsigned long int out_len = 4096; |
190 | 197 | |
191 | 198 | RETVAL = newSVpvn(NULL, 0); /* undef */ |
192 | if (strnEQ(type, "private", 7)) { | |
199 | if (strnEQ(type, "private_short", 16)) { | |
200 | rv = ecc_export_full(out, &out_len, PK_PRIVATE|PK_CURVEOID, &self->key); | |
201 | if (rv != CRYPT_OK) croak("FATAL: ecc_export(PK_PRIVATE|PK_CURVEOID) failed: %s", error_to_string(rv)); | |
202 | RETVAL = newSVpvn((char*)out, out_len); | |
203 | } | |
204 | else if (strnEQ(type, "private", 7)) { | |
193 | 205 | rv = ecc_export_full(out, &out_len, PK_PRIVATE, &self->key); |
194 | 206 | if (rv != CRYPT_OK) croak("FATAL: ecc_export(PK_PRIVATE) failed: %s", error_to_string(rv)); |
207 | RETVAL = newSVpvn((char*)out, out_len); | |
208 | } | |
209 | else if (strnEQ(type, "public_short", 15)) { | |
210 | rv = ecc_export_full(out, &out_len, PK_PUBLIC|PK_CURVEOID, &self->key); | |
211 | if (rv != CRYPT_OK) croak("FATAL: ecc_export(PK_PUBLIC|PK_CURVEOID) failed: %s", error_to_string(rv)); | |
195 | 212 | RETVAL = newSVpvn((char*)out, out_len); |
196 | 213 | } |
197 | 214 | else if (strnEQ(type, "public", 6)) { |
433 | 433 | my ($self, $type, $password, $cipher) = @_; |
434 | 434 | my $key = $self->export_key_der($type||''); |
435 | 435 | return unless $key; |
436 | return der_to_pem($key, "EC PRIVATE KEY", $password, $cipher) if $type eq 'private'; | |
437 | return der_to_pem($key, "PUBLIC KEY") if $type eq 'public' || $type eq 'public_compressed'; | |
436 | return der_to_pem($key, "EC PRIVATE KEY", $password, $cipher) if substr($type, 0, 7) eq 'private'; | |
437 | return der_to_pem($key, "PUBLIC KEY") if substr($type,0, 6) eq 'public'; | |
438 | 438 | } |
439 | 439 | |
440 | 440 | sub export_key_jwk { |
1026 | 1026 | #or |
1027 | 1027 | my $public_der = $pk->export_key_der('public'); |
1028 | 1028 | |
1029 | Since CryptX-0.36 C<export_key_der> can also export keys in a format | |
1030 | that does not explicitely contain curve parameters but only curve OID. | |
1031 | ||
1032 | my $private_der = $pk->export_key_der('private_short'); | |
1033 | #or | |
1034 | my $public_der = $pk->export_key_der('public_short'); | |
1035 | ||
1029 | 1036 | =head2 export_key_pem |
1030 | 1037 | |
1031 | 1038 | my $private_pem = $pk->export_key_pem('private'); |
1032 | 1039 | #or |
1033 | 1040 | my $public_pem = $pk->export_key_pem('public'); |
1041 | ||
1042 | Since CryptX-0.36 C<export_key_pem> can also export keys in a format | |
1043 | that does not explicitely contain curve parameters but only curve OID. | |
1044 | ||
1045 | my $private_pem = $pk->export_key_pem('private_short'); | |
1046 | #or | |
1047 | my $public_pem = $pk->export_key_pem('public_short'); | |
1034 | 1048 | |
1035 | 1049 | Support for password protected PEM keys |
1036 | 1050 |
73 | 73 | ltc/pk/dsa/dsa_import.o ltc/pk/dsa/dsa_import_hex.o ltc/pk/dsa/dsa_make_key.o ltc/pk/dsa/dsa_shared_secret.o \ |
74 | 74 | ltc/pk/dsa/dsa_sign_hash.o ltc/pk/dsa/dsa_verify_hash.o ltc/pk/dsa/dsa_verify_key.o ltc/pk/ecc/ecc.o \ |
75 | 75 | ltc/pk/ecc/ecc_ansi_x963_export.o ltc/pk/ecc/ecc_ansi_x963_import.o ltc/pk/ecc/ecc_decrypt_key.o \ |
76 | ltc/pk/ecc/ecc_dp_clear.o ltc/pk/ecc/ecc_dp_from_oid.o ltc/pk/ecc/ecc_dp_from_params.o ltc/pk/ecc/ecc_dp_init.o \ | |
77 | ltc/pk/ecc/ecc_dp_set.o ltc/pk/ecc/ecc_encrypt_key.o ltc/pk/ecc/ecc_export.o ltc/pk/ecc/ecc_export_full.o \ | |
76 | ltc/pk/ecc/ecc_dp_clear.o ltc/pk/ecc/ecc_dp_fill_from_sets.o ltc/pk/ecc/ecc_dp_from_oid.o \ | |
77 | ltc/pk/ecc/ecc_dp_from_params.o ltc/pk/ecc/ecc_dp_init.o ltc/pk/ecc/ecc_dp_set.o \ | |
78 | ltc/pk/ecc/ecc_encrypt_key.o ltc/pk/ecc/ecc_export.o ltc/pk/ecc/ecc_export_full.o \ | |
78 | 79 | ltc/pk/ecc/ecc_export_raw.o ltc/pk/ecc/ecc_free.o ltc/pk/ecc/ecc_get_size.o ltc/pk/ecc/ecc_import.o \ |
79 | 80 | ltc/pk/ecc/ecc_import_full.o ltc/pk/ecc/ecc_import_pkcs8.o ltc/pk/ecc/ecc_import_raw.o \ |
80 | 81 | ltc/pk/ecc/ecc_make_key.o ltc/pk/ecc/ecc_shared_secret.o ltc/pk/ecc/ecc_sign_hash.o ltc/pk/ecc/ecc_sizes.o \ |
73 | 73 | ltc/pk/dsa/dsa_import.obj ltc/pk/dsa/dsa_import_hex.obj ltc/pk/dsa/dsa_make_key.obj ltc/pk/dsa/dsa_shared_secret.obj \ |
74 | 74 | ltc/pk/dsa/dsa_sign_hash.obj ltc/pk/dsa/dsa_verify_hash.obj ltc/pk/dsa/dsa_verify_key.obj ltc/pk/ecc/ecc.obj \ |
75 | 75 | ltc/pk/ecc/ecc_ansi_x963_export.obj ltc/pk/ecc/ecc_ansi_x963_import.obj ltc/pk/ecc/ecc_decrypt_key.obj \ |
76 | ltc/pk/ecc/ecc_dp_clear.obj ltc/pk/ecc/ecc_dp_from_oid.obj ltc/pk/ecc/ecc_dp_from_params.obj ltc/pk/ecc/ecc_dp_init.obj \ | |
77 | ltc/pk/ecc/ecc_dp_set.obj ltc/pk/ecc/ecc_encrypt_key.obj ltc/pk/ecc/ecc_export.obj ltc/pk/ecc/ecc_export_full.obj \ | |
76 | ltc/pk/ecc/ecc_dp_clear.obj ltc/pk/ecc/ecc_dp_fill_from_sets.obj ltc/pk/ecc/ecc_dp_from_oid.obj \ | |
77 | ltc/pk/ecc/ecc_dp_from_params.obj ltc/pk/ecc/ecc_dp_init.obj ltc/pk/ecc/ecc_dp_set.obj \ | |
78 | ltc/pk/ecc/ecc_encrypt_key.obj ltc/pk/ecc/ecc_export.obj ltc/pk/ecc/ecc_export_full.obj \ | |
78 | 79 | ltc/pk/ecc/ecc_export_raw.obj ltc/pk/ecc/ecc_free.obj ltc/pk/ecc/ecc_get_size.obj ltc/pk/ecc/ecc_import.obj \ |
79 | 80 | ltc/pk/ecc/ecc_import_full.obj ltc/pk/ecc/ecc_import_pkcs8.obj ltc/pk/ecc/ecc_import_raw.obj \ |
80 | 81 | ltc/pk/ecc/ecc_make_key.obj ltc/pk/ecc/ecc_shared_secret.obj ltc/pk/ecc/ecc_sign_hash.obj ltc/pk/ecc/ecc_sizes.obj \ |
2 | 2 | enum { |
3 | 3 | PK_PUBLIC=0, |
4 | 4 | PK_PRIVATE=1, |
5 | PK_PUBLIC_COMPRESSED=2 /* used only when exporting public ECC key */ | |
5 | PK_PUBLIC_COMPRESSED=2, /* used only when exporting public ECC key */ | |
6 | PK_CURVEOID=4 /* used only when exporting public ECC key */ | |
6 | 7 | }; |
7 | 8 | |
8 | 9 | /* Indicates standard output formats that can be read e.g. by OpenSSL or GnuTLS */ |
297 | 298 | int ecc_get_size(ecc_key *key); |
298 | 299 | |
299 | 300 | int ecc_dp_init(ltc_ecc_set_type *dp); |
300 | int ecc_dp_set(ltc_ecc_set_type *dp, char *ch_prime, char *ch_A, char *ch_B, char *ch_order, char *ch_Gx, char *ch_Gy, unsigned long cofactor, char *ch_name); | |
301 | int ecc_dp_set(ltc_ecc_set_type *dp, char *ch_prime, char *ch_A, char *ch_B, char *ch_order, char *ch_Gx, char *ch_Gy, unsigned long cofactor, char *ch_name, char *oid); | |
301 | 302 | int ecc_dp_set_bn(ltc_ecc_set_type *dp, void *a, void *b, void *prime, void *order, void *gx, void *gy, unsigned long cofactor); |
302 | 303 | int ecc_dp_set_by_oid(ltc_ecc_set_type *dp, unsigned long *oid, unsigned long oidsize); |
304 | int ecc_dp_fill_from_sets(ltc_ecc_set_type *dp); | |
303 | 305 | int ecc_dp_clear(ltc_ecc_set_type *dp); |
304 | ||
305 | 306 | |
306 | 307 | int ecc_make_key(prng_state *prng, int wprng, int keysize, ecc_key *key); |
307 | 308 | int ecc_make_key_ex(prng_state *prng, int wprng, ecc_key *key, const ltc_ecc_set_type *dp); |
26 | 26 | if (dp->order != NULL) { XFREE(dp->order); dp->order = NULL; } |
27 | 27 | if (dp->Gx != NULL) { XFREE(dp->Gx ); dp->Gx = NULL; } |
28 | 28 | if (dp->Gy != NULL) { XFREE(dp->Gy ); dp->Gy = NULL; } |
29 | dp->cofactor = 0; | |
29 | dp->cofactor = 0; | |
30 | dp->oid.OIDlen = 0; | |
30 | 31 | |
31 | 32 | return CRYPT_OK; |
32 | 33 | } |
0 | /* LibTomCrypt, modular cryptographic library -- Tom St Denis | |
1 | * | |
2 | * LibTomCrypt is a library that provides various cryptographic | |
3 | * algorithms in a highly modular and flexible manner. | |
4 | * | |
5 | * The library is free for all purposes without any express | |
6 | * guarantee it works. | |
7 | * | |
8 | */ | |
9 | ||
10 | #include "tomcrypt.h" | |
11 | ||
12 | #ifdef LTC_MECC | |
13 | ||
14 | /* search known curve by curve parameters and fill in missing parameters into dp | |
15 | * we assume every parameter has the same case (usually uppercase) and no leading zeros | |
16 | */ | |
17 | int ecc_dp_fill_from_sets(ltc_ecc_set_type *dp) | |
18 | { | |
19 | ltc_ecc_set_type params; | |
20 | int x; | |
21 | ||
22 | if (!dp) return CRYPT_INVALID_ARG; | |
23 | if (dp->oid.OIDlen > 0) return CRYPT_OK; | |
24 | if (!dp->prime || !dp->A || !dp->B || !dp->order || !dp->Gx || !dp->Gy || dp->cofactor == 0) return CRYPT_INVALID_ARG; | |
25 | ||
26 | for (x = 0; ltc_ecc_sets[x].size != 0; x++) { | |
27 | if (XSTRCMP(ltc_ecc_sets[x].prime, dp->prime) == 0 && | |
28 | XSTRCMP(ltc_ecc_sets[x].A, dp->A) == 0 && | |
29 | XSTRCMP(ltc_ecc_sets[x].B, dp->B) == 0 && | |
30 | XSTRCMP(ltc_ecc_sets[x].order, dp->order) == 0 && | |
31 | XSTRCMP(ltc_ecc_sets[x].Gx, dp->Gx) == 0 && | |
32 | XSTRCMP(ltc_ecc_sets[x].Gy, dp->Gy) == 0 && | |
33 | ltc_ecc_sets[x].cofactor == dp->cofactor) { | |
34 | ||
35 | params = ltc_ecc_sets[x]; | |
36 | ||
37 | /* copy oid */ | |
38 | dp->oid.OIDlen = params.oid.OIDlen; | |
39 | XMEMCPY(dp->oid.OID, params.oid.OID, dp->oid.OIDlen * sizeof(dp->oid.OID[0])); | |
40 | ||
41 | /* copy name */ | |
42 | if (dp->name != NULL) XFREE(dp->name); | |
43 | if ((dp->name = XMALLOC(1+strlen(params.name))) == NULL) return CRYPT_MEM; | |
44 | strcpy(dp->name, params.name); | |
45 | ||
46 | return CRYPT_OK; | |
47 | } | |
48 | } | |
49 | ||
50 | return CRYPT_INVALID_ARG; | |
51 | } | |
52 | ||
53 | #endif |
60 | 60 | len = (unsigned long)strlen(ltc_ecc_sets[i].name); |
61 | 61 | if ((dp->name = XMALLOC(1+len)) == NULL) goto cleanup7; |
62 | 62 | strncpy(dp->name, ltc_ecc_sets[i].name, 1+len); |
63 | /* oid */ | |
64 | dp->oid.OIDlen = ltc_ecc_sets[i].oid.OIDlen; | |
65 | XMEMCPY(dp->oid.OID, ltc_ecc_sets[i].oid.OID, dp->oid.OIDlen * sizeof(dp->oid.OID[0])); | |
63 | 66 | /* done - success */ |
64 | 67 | return CRYPT_OK; |
65 | 68 |
54 | 54 | /* cofactor & size */ |
55 | 55 | dp->cofactor = cofactor; |
56 | 56 | dp->size = mp_unsigned_bin_size(prime); |
57 | /* name */ | |
58 | if ((dp->name = XMALLOC(7)) == NULL) goto cleanup7; | |
59 | strcpy(dp->name, "custom"); /* XXX-TODO check this */ | |
57 | /* see if we can fill in the missing parameters from known curves */ | |
58 | if ((ecc_dp_fill_from_sets(dp)) != CRYPT_OK) { | |
59 | /* custom name */ | |
60 | if ((dp->name = XMALLOC(7)) == NULL) goto cleanup7; | |
61 | strcpy(dp->name, "custom"); /* XXX-TODO check this */ | |
62 | /* no oid */ | |
63 | dp->oid.OIDlen = 0; | |
64 | } | |
60 | 65 | /* done - success */ |
61 | 66 | return CRYPT_OK; |
62 | 67 |
12 | 12 | */ |
13 | 13 | |
14 | 14 | #include "tomcrypt.h" |
15 | #include <errno.h> | |
15 | 16 | |
16 | 17 | #ifdef LTC_MECC |
17 | 18 | |
18 | int ecc_dp_set(ltc_ecc_set_type *dp, char *ch_prime, char *ch_A, char *ch_B, char *ch_order, char *ch_Gx, char *ch_Gy, unsigned long cofactor, char *ch_name) | |
19 | int ecc_dp_set(ltc_ecc_set_type *dp, char *ch_prime, char *ch_A, char *ch_B, char *ch_order, char *ch_Gx, char *ch_Gy, unsigned long cofactor, char *ch_name, char *oid) | |
19 | 20 | { |
20 | 21 | unsigned long l_name, l_prime, l_A, l_B, l_order, l_Gx, l_Gy; |
21 | 22 | |
22 | 23 | if (!dp || !ch_prime || !ch_A || !ch_B || !ch_order || !ch_Gx || !ch_Gy || cofactor==0) return CRYPT_INVALID_ARG; |
23 | 24 | |
24 | l_name = (unsigned long)strlen(ch_name); | |
25 | 25 | l_prime = (unsigned long)strlen(ch_prime); |
26 | 26 | l_A = (unsigned long)strlen(ch_A); |
27 | 27 | l_B = (unsigned long)strlen(ch_B); |
47 | 47 | if (dp->Gx != NULL) { XFREE(dp->Gx ); dp->Gx = NULL; } |
48 | 48 | if (dp->Gy != NULL) { XFREE(dp->Gy ); dp->Gy = NULL; } |
49 | 49 | |
50 | dp->name = XMALLOC(1+l_name); strncpy(dp->name, ch_name, 1+l_name); | |
51 | 50 | dp->prime = XMALLOC(1+l_prime); strncpy(dp->prime, ch_prime, 1+l_prime); |
52 | 51 | dp->A = XMALLOC(1+l_A); strncpy(dp->A, ch_A, 1+l_A); |
53 | 52 | dp->B = XMALLOC(1+l_B); strncpy(dp->B, ch_B, 1+l_B); |
55 | 54 | dp->Gx = XMALLOC(1+l_Gx); strncpy(dp->Gx, ch_Gx, 1+l_Gx); |
56 | 55 | dp->Gy = XMALLOC(1+l_Gy); strncpy(dp->Gy, ch_Gy, 1+l_Gy); |
57 | 56 | |
57 | /* optional parameters */ | |
58 | if (ch_name == NULL && oid == NULL) { | |
59 | (void)ecc_dp_fill_from_sets(dp); | |
60 | } | |
61 | else { | |
62 | if (ch_name != NULL) { | |
63 | l_name = (unsigned long)strlen(ch_name); | |
64 | dp->name = XMALLOC(1+l_name); | |
65 | strncpy(dp->name, ch_name, 1+l_name); | |
66 | } | |
67 | ||
68 | if (oid != NULL) { | |
69 | char *end_ptr; | |
70 | unsigned int i = 0; | |
71 | unsigned long val; | |
72 | ||
73 | end_ptr = oid; | |
74 | while (i < sizeof(dp->oid.OID)/sizeof(dp->oid.OID[0]) && *oid != '\0') { | |
75 | errno = 0; | |
76 | val = strtoul(oid, &end_ptr, 10); | |
77 | if (errno != 0 || oid == end_ptr) break; // parsing failed | |
78 | if (val > 0xFFFFFFFF) break; // x64 check | |
79 | dp->oid.OID[i++] = val; | |
80 | oid = end_ptr; | |
81 | if (*oid != '.') break; | |
82 | oid++; | |
83 | } | |
84 | if (i == 0 || *end_ptr != '\0') return CRYPT_INVALID_ARG; | |
85 | dp->oid.OIDlen = i; | |
86 | } | |
87 | } | |
88 | ||
89 | /* in case the parameters are really custom (unlikely) */ | |
90 | if (dp->name == NULL) { | |
91 | dp->name = XMALLOC(7); | |
92 | strcpy(dp->name, "custom"); | |
93 | dp->oid.OIDlen = 0; | |
94 | } | |
95 | ||
58 | 96 | return CRYPT_OK; |
59 | 97 | } |
60 | 98 |
32 | 32 | unsigned long len_a, len_b, len_k, len_g, len_xy; |
33 | 33 | unsigned long cofactor, one = 1; |
34 | 34 | oid_st oid; |
35 | ltc_asn1_list seq_fieldid[2], seq_curve[2], seq_ecparams[6], seq_priv[4]; | |
35 | ltc_asn1_list seq_fieldid[2], seq_curve[2], seq_ecparams[6], seq_priv[4], asn_ecparams[1]; | |
36 | 36 | |
37 | 37 | LTC_ARGCHK(out != NULL); |
38 | 38 | LTC_ARGCHK(outlen != NULL); |
77 | 77 | /* we support only prime-field EC */ |
78 | 78 | if ((err = pk_get_oid(EC_PRIME_FIELD, &oid)) != CRYPT_OK) goto error; |
79 | 79 | |
80 | /* FieldID SEQUENCE */ | |
81 | LTC_SET_ASN1(seq_fieldid, 0, LTC_ASN1_OBJECT_IDENTIFIER, oid.OID, oid.OIDlen); | |
82 | LTC_SET_ASN1(seq_fieldid, 1, LTC_ASN1_INTEGER, prime, 1UL); | |
80 | if (type & PK_CURVEOID) { | |
81 | /* from http://tools.ietf.org/html/rfc5912 | |
83 | 82 | |
84 | /* Curve SEQUENCE */ | |
85 | LTC_SET_ASN1(seq_curve, 0, LTC_ASN1_OCTET_STRING, bin_a, len_a); | |
86 | LTC_SET_ASN1(seq_curve, 1, LTC_ASN1_OCTET_STRING, bin_b, len_b); | |
83 | ECParameters ::= CHOICE { | |
84 | namedCurve CURVE.&id({NamedCurve}) # OBJECT | |
85 | } | |
86 | */ | |
87 | 87 | |
88 | /* ECParameters SEQUENCE */ | |
89 | LTC_SET_ASN1(seq_ecparams, 0, LTC_ASN1_SHORT_INTEGER, &one, 1UL); | |
90 | LTC_SET_ASN1(seq_ecparams, 1, LTC_ASN1_SEQUENCE, seq_fieldid, 2UL); | |
91 | LTC_SET_ASN1(seq_ecparams, 2, LTC_ASN1_SEQUENCE, seq_curve, 2UL); | |
92 | LTC_SET_ASN1(seq_ecparams, 3, LTC_ASN1_OCTET_STRING, bin_g, len_g); | |
93 | LTC_SET_ASN1(seq_ecparams, 4, LTC_ASN1_INTEGER, order, 1UL); | |
94 | LTC_SET_ASN1(seq_ecparams, 5, LTC_ASN1_SHORT_INTEGER, &cofactor, 1UL); | |
88 | /* BEWARE: exporting PK_CURVEOID with custom OID means we're unable to read the curve again */ | |
89 | if (key->dp->oid.OIDlen == 0) { err = CRYPT_INVALID_ARG; goto error; } | |
90 | ||
91 | /* ECParameters used by ECPrivateKey or SubjectPublicKeyInfo below */ | |
92 | LTC_SET_ASN1(asn_ecparams, 0, LTC_ASN1_OBJECT_IDENTIFIER, key->dp->oid.OID, key->dp->oid.OIDlen); | |
93 | type &= ~PK_CURVEOID; | |
94 | } | |
95 | else { | |
96 | /* from http://tools.ietf.org/html/rfc3279 | |
97 | ||
98 | ECParameters ::= SEQUENCE { # SEQUENCE | |
99 | version INTEGER { ecpVer1(1) } (ecpVer1), # INTEGER :01 | |
100 | FieldID ::= SEQUENCE { # SEQUENCE | |
101 | fieldType FIELD-ID.&id({IOSet}), # OBJECT :prime-field | |
102 | parameters FIELD-ID.&Type({IOSet}{@fieldType}) # INTEGER | |
103 | } | |
104 | Curve ::= SEQUENCE { # SEQUENCE | |
105 | a FieldElement ::= OCTET STRING # OCTET STRING | |
106 | b FieldElement ::= OCTET STRING # OCTET STRING | |
107 | seed BIT STRING OPTIONAL | |
108 | } | |
109 | base ECPoint ::= OCTET STRING # OCTET STRING | |
110 | order INTEGER, # INTEGER | |
111 | cofactor INTEGER OPTIONAL # INTEGER | |
112 | } | |
113 | */ | |
114 | ||
115 | /* FieldID SEQUENCE */ | |
116 | LTC_SET_ASN1(seq_fieldid, 0, LTC_ASN1_OBJECT_IDENTIFIER, oid.OID, oid.OIDlen); | |
117 | LTC_SET_ASN1(seq_fieldid, 1, LTC_ASN1_INTEGER, prime, 1UL); | |
118 | ||
119 | /* Curve SEQUENCE */ | |
120 | LTC_SET_ASN1(seq_curve, 0, LTC_ASN1_OCTET_STRING, bin_a, len_a); | |
121 | LTC_SET_ASN1(seq_curve, 1, LTC_ASN1_OCTET_STRING, bin_b, len_b); | |
122 | ||
123 | /* ECParameters SEQUENCE */ | |
124 | LTC_SET_ASN1(seq_ecparams, 0, LTC_ASN1_SHORT_INTEGER, &one, 1UL); | |
125 | LTC_SET_ASN1(seq_ecparams, 1, LTC_ASN1_SEQUENCE, seq_fieldid, 2UL); | |
126 | LTC_SET_ASN1(seq_ecparams, 2, LTC_ASN1_SEQUENCE, seq_curve, 2UL); | |
127 | LTC_SET_ASN1(seq_ecparams, 3, LTC_ASN1_OCTET_STRING, bin_g, len_g); | |
128 | LTC_SET_ASN1(seq_ecparams, 4, LTC_ASN1_INTEGER, order, 1UL); | |
129 | LTC_SET_ASN1(seq_ecparams, 5, LTC_ASN1_SHORT_INTEGER, &cofactor, 1UL); | |
130 | ||
131 | /* ECParameters used by ECPrivateKey or SubjectPublicKeyInfo below */ | |
132 | LTC_SET_ASN1(asn_ecparams, 0, LTC_ASN1_SEQUENCE, seq_ecparams, 6UL); | |
133 | } | |
95 | 134 | |
96 | 135 | if (type == PK_PRIVATE) { |
97 | 136 | /* private key format: http://tools.ietf.org/html/rfc5915 |
99 | 138 | ECPrivateKey ::= SEQUENCE { # SEQUENCE |
100 | 139 | version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), # INTEGER :01 |
101 | 140 | privateKey OCTET STRING, # OCTET STRING |
102 | [0] ECParameters ::= SEQUENCE { # SEQUENCE | |
103 | version INTEGER { ecpVer1(1) } (ecpVer1), # INTEGER :01 | |
104 | FieldID ::= SEQUENCE { # SEQUENCE | |
105 | fieldType FIELD-ID.&id({IOSet}), # OBJECT :prime-field | |
106 | parameters FIELD-ID.&Type({IOSet}{@fieldType}) # INTEGER | |
107 | } | |
108 | Curve ::= SEQUENCE { # SEQUENCE | |
109 | a FieldElement ::= OCTET STRING # OCTET STRING | |
110 | b FieldElement ::= OCTET STRING # OCTET STRING | |
111 | seed BIT STRING OPTIONAL | |
112 | } | |
113 | base ECPoint ::= OCTET STRING # OCTET STRING | |
114 | order INTEGER, # INTEGER | |
115 | cofactor INTEGER OPTIONAL # INTEGER | |
116 | } | |
117 | [1] publicKey # BIT STRING | |
141 | [0] ECParameters # see above | |
142 | [1] publicKey # BIT STRING | |
118 | 143 | } |
119 | 144 | */ |
120 | 145 | |
123 | 148 | if (len_k > sizeof(bin_k)) { err = CRYPT_BUFFER_OVERFLOW; goto error; } |
124 | 149 | if ((err = mp_to_unsigned_bin(key->k, bin_k)) != CRYPT_OK) goto error; |
125 | 150 | |
126 | LTC_SET_ASN1(seq_priv, 0, LTC_ASN1_SHORT_INTEGER, &one, 1UL); | |
127 | LTC_SET_ASN1(seq_priv, 1, LTC_ASN1_OCTET_STRING, bin_k, len_k); | |
128 | LTC_SET_ASN1(seq_priv, 2, LTC_ASN1_SEQUENCE, seq_ecparams, 6UL); | |
129 | LTC_SET_ASN1(seq_priv, 3, LTC_ASN1_RAW_BIT_STRING, bin_xy, 8*len_xy); | |
151 | LTC_SET_ASN1(seq_priv, 0, LTC_ASN1_SHORT_INTEGER, &one, 1UL); | |
152 | LTC_SET_ASN1(seq_priv, 1, LTC_ASN1_OCTET_STRING, bin_k, len_k); | |
153 | LTC_SET_ASN1(seq_priv, 2, asn_ecparams[0].type, asn_ecparams[0].data, asn_ecparams[0].size); | |
154 | LTC_SET_ASN1(seq_priv, 3, LTC_ASN1_RAW_BIT_STRING, bin_xy, 8*len_xy); | |
130 | 155 | seq_priv[2].tag = 0xA0; |
131 | 156 | seq_priv[3].tag = 0xA1; |
132 | 157 | |
138 | 163 | SubjectPublicKeyInfo ::= SEQUENCE { # SEQUENCE |
139 | 164 | AlgorithmIdentifier ::= SEQUENCE { # SEQUENCE |
140 | 165 | algorithm OBJECT IDENTIFIER # OBJECT :id-ecPublicKey |
141 | ECParameters ::= SEQUENCE { # SEQUENCE | |
142 | version INTEGER { ecpVer1(1) } (ecpVer1), # INTEGER :01 | |
143 | FieldID ::= SEQUENCE { # SEQUENCE | |
144 | fieldType FIELD-ID.&id({IOSet}), # OBJECT :prime-field | |
145 | parameters FIELD-ID.&Type({IOSet}{@fieldType}) # INTEGER | |
146 | } | |
147 | Curve ::= SEQUENCE { # SEQUENCE | |
148 | a FieldElement ::= OCTET STRING # OCTET STRING | |
149 | b FieldElement ::= OCTET STRING # OCTET STRING | |
150 | seed BIT STRING OPTIONAL | |
151 | } | |
152 | base ECPoint ::= OCTET STRING # OCTET STRING | |
153 | order INTEGER, # INTEGER | |
154 | cofactor INTEGER OPTIONAL # INTEGER | |
155 | } | |
166 | ECParameters # see above | |
156 | 167 | } |
157 | 168 | subjectPublicKey BIT STRING # BIT STRING |
158 | 169 | } |
159 | 170 | */ |
160 | ||
161 | 171 | err = der_encode_subject_public_key_info( out, outlen, |
162 | 172 | PKA_EC, bin_xy, len_xy, |
163 | LTC_ASN1_SEQUENCE, seq_ecparams, 6 ); | |
173 | asn_ecparams[0].type, asn_ecparams[0].data, asn_ecparams[0].size ); | |
164 | 174 | } |
165 | 175 | |
166 | 176 | error: |
0 | 0 | use strict; |
1 | 1 | use warnings; |
2 | use Test::More tests => 108; | |
2 | use Test::More tests => 121; | |
3 | 3 | |
4 | 4 | use Crypt::PK::ECC qw(ecc_encrypt ecc_decrypt ecc_sign_message ecc_verify_message ecc_sign_hash ecc_verify_hash ecc_shared_secret); |
5 | 5 | |
136 | 136 | #ok($k->export_key_pem('public'), 'export_key_pem pub'); |
137 | 137 | ok($k->export_key_der('private'), 'export_key_der pri'); |
138 | 138 | ok($k->export_key_der('public'), 'export_key_der pub'); |
139 | ok($k->export_key_der('private_short'), 'export_key_der pri_short'); | |
140 | ok($k->export_key_der('public_short'), 'export_key_der pub_short'); | |
139 | 141 | } |
140 | 142 | |
141 | 143 | { |
157 | 159 | } |
158 | 160 | |
159 | 161 | for my $priv (qw/openssl_ec-short.pem openssl_ec-short.der/) { |
160 | my $k = Crypt::PK::ECC->new("t/data/$priv"); | |
162 | my $f = "t/data/$priv"; | |
163 | my $k = Crypt::PK::ECC->new($f); | |
161 | 164 | ok($k, "load $priv"); |
162 | 165 | ok($k->is_private, "is_private $priv"); |
163 | 166 | is($k->size, 32, "size $priv"); |
164 | 167 | is(uc($k->key2hash->{pub_x}), 'A01532A3C0900053DE60FBEFEFCCA58793301598D308B41E6F4E364E388C2711', "key2hash $priv"); |
165 | 168 | is(uc($k->curve2hash->{prime}), 'FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF', "curve2hash $priv"); |
166 | 169 | is($k->key2hash->{curve_name}, "secp256r1", "EC curve_name is lowercase"); |
170 | is($k->export_key_der('private_short'), read_file($f), 'export_key_der private_oid') if (substr($priv, -3) eq "der"); | |
171 | is($k->export_key_pem('private_short'), read_file($f), 'export_key_pem private_oid') if (substr($priv, -3) eq "pem"); | |
167 | 172 | } |
168 | 173 | |
169 | 174 | for my $pub (qw/openssl_ec-short.pub.pem openssl_ec-short.pub.der/) { |
170 | my $k = Crypt::PK::ECC->new("t/data/$pub"); | |
175 | my $f = "t/data/$pub"; | |
176 | my $k = Crypt::PK::ECC->new($f); | |
171 | 177 | ok($k, "load $pub"); |
172 | 178 | ok(!$k->is_private, "is_private $pub"); |
173 | 179 | is($k->size, 32, "$pub size"); |
174 | 180 | is(uc($k->key2hash->{pub_x}), 'A01532A3C0900053DE60FBEFEFCCA58793301598D308B41E6F4E364E388C2711', "key2hash $pub"); |
175 | 181 | is($k->key2hash->{curve_name}, "secp256r1", "EC curve_name is lowercase"); |
182 | is($k->export_key_der('public_short'), read_file($f), 'export_key_der public_short') if (substr($pub, -3) eq "der"); | |
183 | is($k->export_key_pem('public_short'), read_file($f), 'export_key_pem public_short') if (substr($pub, -3) eq "pem"); | |
176 | 184 | } |
177 | 185 | |
178 | 186 | { |
180 | 188 | eval { $k->export_key_pem('public'); }; |
181 | 189 | ok($@, 'key not generated'); |
182 | 190 | |
191 | # known curves lookup | |
183 | 192 | my $params = $Crypt::PK::ECC::curve{secp384r1}; |
193 | $k = Crypt::PK::ECC->new; | |
184 | 194 | ok($k->generate_key($params), "generate_key hash params"); |
185 | } | |
195 | is($k->key2hash->{curve_name}, 'secp384r1', "key2hash curve_name"); | |
196 | is($k->key2hash->{curve_oid}, $params->{oid}, "key2hash curve_oid"); | |
197 | ok($k->export_key_der('private_short'), "export_key_der auto oid"); | |
198 | ||
199 | $k = Crypt::PK::ECC->new; | |
200 | ok($k->generate_key({ %$params, A => '0' }), "generate_key invalid auto oid"); | |
201 | is($k->key2hash->{curve_name}, 'custom', "key2hash custom curve_name"); | |
202 | ok(!exists($k->key2hash->{curve_oid}), "key2hash curve_oid doesn't exist"); | |
203 | eval { $k->export_key_der('private_short'); }; | |
204 | ok($@, "export_key_der invalid auto oid"); | |
205 | } |