2 * Portions Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
3 * Portions Copyright (C) 1999-2001 Internet Software Consortium.
4 * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
11 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
13 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
16 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 * Principal Author: Brian Wellington
21 * $Id: dst_parse.c,v 1.31.2.3 2004/03/09 06:11:40 marka Exp $
26 #include <isc/base64.h>
28 #include <isc/fsaccess.h>
31 #include <isc/string.h>
34 #include "dst_internal.h"
35 #include "dst_parse.h"
36 #include "dst/result.h"
39 #define PRIVATE_KEY_STR "Private-key-format:"
40 #define ALGORITHM_STR "Algorithm:"
44 #define HMACMD5_STR "HMAC_MD5"
51 static struct parse_map map
[] = {
52 {TAG_RSA_MODULUS
, "Modulus:"},
53 {TAG_RSA_PUBLICEXPONENT
, "PublicExponent:"},
54 {TAG_RSA_PRIVATEEXPONENT
, "PrivateExponent:"},
55 {TAG_RSA_PRIME1
, "Prime1:"},
56 {TAG_RSA_PRIME2
, "Prime2:"},
57 {TAG_RSA_EXPONENT1
, "Exponent1:"},
58 {TAG_RSA_EXPONENT2
, "Exponent2:"},
59 {TAG_RSA_COEFFICIENT
, "Coefficient:"},
61 {TAG_DH_PRIME
, "Prime(p):"},
62 {TAG_DH_GENERATOR
, "Generator(g):"},
63 {TAG_DH_PRIVATE
, "Private_value(x):"},
64 {TAG_DH_PUBLIC
, "Public_value(y):"},
66 {TAG_DSA_PRIME
, "Prime(p):"},
67 {TAG_DSA_SUBPRIME
, "Subprime(q):"},
68 {TAG_DSA_BASE
, "Base(g):"},
69 {TAG_DSA_PRIVATE
, "Private_value(x):"},
70 {TAG_DSA_PUBLIC
, "Public_value(y):"},
72 {TAG_HMACMD5_KEY
, "Key:"},
77 find_value(const char *s
, const unsigned int alg
) {
81 if (map
[i
].tag
== NULL
)
83 else if (strcasecmp(s
, map
[i
].tag
) == 0 &&
84 TAG_ALG(map
[i
].value
) == alg
)
85 return (map
[i
].value
);
90 find_tag(const int value
) {
94 if (map
[i
].tag
== NULL
)
96 else if (value
== map
[i
].value
)
102 check_rsa(const dst_private_t
*priv
) {
104 if (priv
->nelements
!= RSA_NTAGS
)
106 for (i
= 0; i
< RSA_NTAGS
; i
++) {
107 for (j
= 0; j
< priv
->nelements
; j
++)
108 if (priv
->elements
[j
].tag
== TAG(DST_ALG_RSAMD5
, i
))
110 if (j
== priv
->nelements
)
117 check_dh(const dst_private_t
*priv
) {
119 if (priv
->nelements
!= DH_NTAGS
)
121 for (i
= 0; i
< DH_NTAGS
; i
++) {
122 for (j
= 0; j
< priv
->nelements
; j
++)
123 if (priv
->elements
[j
].tag
== TAG(DST_ALG_DH
, i
))
125 if (j
== priv
->nelements
)
132 check_dsa(const dst_private_t
*priv
) {
134 if (priv
->nelements
!= DSA_NTAGS
)
136 for (i
= 0; i
< DSA_NTAGS
; i
++) {
137 for (j
= 0; j
< priv
->nelements
; j
++)
138 if (priv
->elements
[j
].tag
== TAG(DST_ALG_DSA
, i
))
140 if (j
== priv
->nelements
)
147 check_hmac_md5(const dst_private_t
*priv
) {
148 if (priv
->nelements
!= HMACMD5_NTAGS
)
150 if (priv
->elements
[0].tag
!= TAG_HMACMD5_KEY
)
156 check_data(const dst_private_t
*priv
, const unsigned int alg
) {
157 /* XXXVIX this switch statement is too sparse to gen a jump table. */
160 return (check_rsa(priv
));
162 return (check_dh(priv
));
164 return (check_dsa(priv
));
165 case DST_ALG_HMACMD5
:
166 return (check_hmac_md5(priv
));
168 return (DST_R_UNSUPPORTEDALG
);
173 dst__privstruct_free(dst_private_t
*priv
, isc_mem_t
*mctx
) {
178 for (i
= 0; i
< priv
->nelements
; i
++) {
179 if (priv
->elements
[i
].data
== NULL
)
181 memset(priv
->elements
[i
].data
, 0, MAXFIELDSIZE
);
182 isc_mem_put(mctx
, priv
->elements
[i
].data
, MAXFIELDSIZE
);
188 dst__privstruct_parsefile(dst_key_t
*key
, const char *filename
,
189 isc_mem_t
*mctx
, dst_private_t
*priv
)
191 int n
= 0, major
, minor
;
193 isc_lex_t
*lex
= NULL
;
195 unsigned int opt
= ISC_LEXOPT_EOL
;
200 REQUIRE(priv
!= NULL
);
202 newfilenamelen
= strlen(filename
) + 9;
203 newfilename
= isc_mem_get(mctx
, newfilenamelen
);
204 if (newfilename
== NULL
)
205 return (ISC_R_NOMEMORY
);
206 ret
= dst__file_addsuffix(newfilename
, newfilenamelen
, filename
,
208 INSIST(ret
== ISC_R_SUCCESS
);
212 ret
= isc_lex_create(mctx
, 1024, &lex
);
213 if (ret
!= ISC_R_SUCCESS
)
216 ret
= isc_lex_openfile(lex
, newfilename
);
217 if (ret
!= ISC_R_SUCCESS
)
220 #define NEXTTOKEN(lex, opt, token) \
222 ret = isc_lex_gettoken(lex, opt, token); \
223 if (ret != ISC_R_SUCCESS) \
227 #define READLINE(lex, opt, token) \
229 NEXTTOKEN(lex, opt, token) \
230 } while ((*token).type != isc_tokentype_eol) \
233 * Read the description line.
235 NEXTTOKEN(lex
, opt
, &token
);
236 if (token
.type
!= isc_tokentype_string
||
237 strcmp(token
.value
.as_pointer
, PRIVATE_KEY_STR
) != 0)
239 ret
= DST_R_INVALIDPRIVATEKEY
;
243 NEXTTOKEN(lex
, opt
, &token
);
244 if (token
.type
!= isc_tokentype_string
||
245 ((char *)token
.value
.as_pointer
)[0] != 'v')
247 ret
= DST_R_INVALIDPRIVATEKEY
;
250 if (sscanf(token
.value
.as_pointer
, "v%d.%d", &major
, &minor
) != 2)
252 ret
= DST_R_INVALIDPRIVATEKEY
;
256 if (major
> MAJOR_VERSION
||
257 (major
== MAJOR_VERSION
&& minor
> MINOR_VERSION
))
259 ret
= DST_R_INVALIDPRIVATEKEY
;
263 READLINE(lex
, opt
, &token
);
266 * Read the algorithm line.
268 NEXTTOKEN(lex
, opt
, &token
);
269 if (token
.type
!= isc_tokentype_string
||
270 strcmp(token
.value
.as_pointer
, ALGORITHM_STR
) != 0)
272 ret
= DST_R_INVALIDPRIVATEKEY
;
276 NEXTTOKEN(lex
, opt
| ISC_LEXOPT_NUMBER
, &token
);
277 if (token
.type
!= isc_tokentype_number
||
278 token
.value
.as_ulong
!= (unsigned long) dst_key_alg(key
))
280 ret
= DST_R_INVALIDPRIVATEKEY
;
284 READLINE(lex
, opt
, &token
);
289 for (n
= 0; n
< MAXFIELDS
; n
++) {
295 ret
= isc_lex_gettoken(lex
, opt
, &token
);
296 if (ret
== ISC_R_EOF
)
298 if (ret
!= ISC_R_SUCCESS
)
300 } while (token
.type
== isc_tokentype_eol
);
302 if (token
.type
!= isc_tokentype_string
) {
303 ret
= DST_R_INVALIDPRIVATEKEY
;
307 memset(&priv
->elements
[n
], 0, sizeof(dst_private_element_t
));
308 tag
= find_value(token
.value
.as_pointer
, dst_key_alg(key
));
309 if (tag
< 0 || TAG_ALG(tag
) != dst_key_alg(key
)) {
310 ret
= DST_R_INVALIDPRIVATEKEY
;
313 priv
->elements
[n
].tag
= tag
;
315 data
= (unsigned char *) isc_mem_get(mctx
, MAXFIELDSIZE
);
319 isc_buffer_init(&b
, data
, MAXFIELDSIZE
);
320 ret
= isc_base64_tobuffer(lex
, &b
, -1);
321 if (ret
!= ISC_R_SUCCESS
)
323 isc_buffer_usedregion(&b
, &r
);
324 priv
->elements
[n
].length
= r
.length
;
325 priv
->elements
[n
].data
= r
.base
;
327 READLINE(lex
, opt
, &token
);
332 if (check_data(priv
, dst_key_alg(key
)) < 0)
336 isc_lex_destroy(&lex
);
337 isc_mem_put(mctx
, newfilename
, newfilenamelen
);
339 return (ISC_R_SUCCESS
);
344 isc_lex_destroy(&lex
);
346 isc_mem_put(mctx
, newfilename
, newfilenamelen
);
349 dst__privstruct_free(priv
, mctx
);
354 dst__privstruct_writefile(const dst_key_t
*key
, const dst_private_t
*priv
,
355 const char *directory
)
360 char filename
[ISC_DIR_NAMEMAX
];
361 char buffer
[MAXFIELDSIZE
* 2];
363 isc_fsaccess_t access
;
365 REQUIRE(priv
!= NULL
);
367 if (check_data(priv
, dst_key_alg(key
)) < 0)
368 return (DST_R_INVALIDPRIVATEKEY
);
370 isc_buffer_init(&b
, filename
, sizeof(filename
));
371 ret
= dst_key_buildfilename(key
, DST_TYPE_PRIVATE
, directory
, &b
);
372 if (ret
!= ISC_R_SUCCESS
)
375 if ((fp
= fopen(filename
, "w")) == NULL
)
376 return (DST_R_WRITEERROR
);
379 isc_fsaccess_add(ISC_FSACCESS_OWNER
,
380 ISC_FSACCESS_READ
| ISC_FSACCESS_WRITE
,
382 (void)isc_fsaccess_set(filename
, access
);
384 /* XXXDCL return value should be checked for full filesystem */
385 fprintf(fp
, "%s v%d.%d\n", PRIVATE_KEY_STR
, MAJOR_VERSION
,
388 fprintf(fp
, "%s %d ", ALGORITHM_STR
, dst_key_alg(key
));
389 /* XXXVIX this switch statement is too sparse to gen a jump table. */
390 switch (dst_key_alg(key
)) {
392 fprintf(fp
, "(RSA)\n");
395 fprintf(fp
, "(DH)\n");
398 fprintf(fp
, "(DSA)\n");
400 case DST_ALG_HMACMD5
:
401 fprintf(fp
, "(HMAC_MD5)\n");
404 fprintf(fp
, "(?)\n");
408 for (i
= 0; i
< priv
->nelements
; i
++) {
413 s
= find_tag(priv
->elements
[i
].tag
);
415 r
.base
= priv
->elements
[i
].data
;
416 r
.length
= priv
->elements
[i
].length
;
417 isc_buffer_init(&b
, buffer
, sizeof(buffer
));
418 iret
= isc_base64_totext(&r
, sizeof(buffer
), "", &b
);
419 if (iret
!= ISC_R_SUCCESS
) {
421 return (DST_R_INVALIDPRIVATEKEY
);
423 isc_buffer_usedregion(&b
, &r
);
425 fprintf(fp
, "%s ", s
);
426 fwrite(r
.base
, 1, r
.length
, fp
);
431 return (ISC_R_SUCCESS
);