]>
Commit | Line | Data |
---|---|---|
3997081b TL |
1 | /* |
2 | * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc. | |
ae566556 | 3 | * Portions Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC") |
0da37b4c | 4 | * Portions Copyright (c) 2012-2014 by Internet Systems Consortium, Inc. ("ISC") |
3997081b TL |
5 | * |
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. | |
9 | * | |
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS | |
11 | * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL | |
12 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL | |
13 | * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT, | |
14 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING | |
15 | * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, | |
16 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION | |
17 | * WITH THE USE OR PERFORMANCE OF THE SOFTWARE. | |
18 | */ | |
19 | /* | |
20 | * This file contains the interface between the DST API and the crypto API. | |
21 | * This is the only file that needs to be changed if the crypto system is | |
22 | * changed. Exported functions are: | |
23 | * void dst_init() Initialize the toolkit | |
20ae1aff | 24 | * int dst_check_algorithm() Function to determines if alg is supported. |
3997081b TL |
25 | * int dst_compare_keys() Function to compare two keys for equality. |
26 | * int dst_sign_data() Incremental signing routine. | |
27 | * int dst_verify_data() Incremental verify routine. | |
28 | * int dst_generate_key() Function to generate new KEY | |
29 | * DST_KEY *dst_read_key() Function to retrieve private/public KEY. | |
30 | * void dst_write_key() Function to write out a key. | |
31 | * DST_KEY *dst_dnskey_to_key() Function to convert DNS KEY RR to a DST | |
32 | * KEY structure. | |
33 | * int dst_key_to_dnskey() Function to return a public key in DNS | |
34 | * format binary | |
20ae1aff FD |
35 | * DST_KEY *dst_buffer_to_key() Convert a data in buffer to KEY |
36 | * int *dst_key_to_buffer() Writes out DST_KEY key material in buffer | |
3997081b TL |
37 | * void dst_free_key() Releases all memory referenced by key structure |
38 | */ | |
39 | ||
40 | #include <stdio.h> | |
41 | #include <errno.h> | |
42 | #include <fcntl.h> | |
43 | #include <stdlib.h> | |
44 | #include <unistd.h> | |
45 | #include <string.h> | |
46 | #include <memory.h> | |
47 | #include <ctype.h> | |
48 | #include <time.h> | |
49 | #include <sys/param.h> | |
50 | #include <sys/stat.h> | |
51 | #include <sys/socket.h> | |
52 | #include <netinet/in.h> | |
439a9b00 | 53 | |
3ac2a573 SR |
54 | #include "cdefs.h" |
55 | #include "osdep.h" | |
439a9b00 | 56 | #include "arpa/nameser.h" |
3997081b TL |
57 | |
58 | #include "dst_internal.h" | |
59 | ||
60 | /* static variables */ | |
61 | static int done_init = 0; | |
62 | dst_func *dst_t_func[DST_MAX_ALGS]; | |
63 | const char *key_file_fmt_str = "Private-key-format: v%s\nAlgorithm: %d (%s)\n"; | |
64 | const char *dst_path = ""; | |
65 | ||
66 | /* internal I/O functions */ | |
67 | static DST_KEY *dst_s_read_public_key(const char *in_name, | |
68 | const unsigned in_id, int in_alg); | |
69 | static int dst_s_read_private_key_file(char *name, DST_KEY *pk_key, | |
70 | unsigned in_id, int in_alg); | |
71 | static int dst_s_write_public_key(const DST_KEY *key); | |
72 | static int dst_s_write_private_key(const DST_KEY *key); | |
73 | ||
74 | /* internal function to set up data structure */ | |
75 | static DST_KEY *dst_s_get_key_struct(const char *name, const int alg, | |
76 | const u_int32_t flags, const int protocol, | |
77 | const int bits); | |
78 | ||
79 | /* | |
80 | * dst_init | |
81 | * This function initializes the Digital Signature Toolkit. | |
82 | * Right now, it just checks the DSTKEYPATH environment variable. | |
83 | * Parameters | |
84 | * none | |
85 | * Returns | |
86 | * none | |
87 | */ | |
88 | void | |
89 | dst_init() | |
90 | { | |
91 | char *s; | |
92 | unsigned len; | |
93 | ||
94 | if (done_init != 0) | |
95 | return; | |
96 | done_init = 1; | |
97 | ||
98 | s = getenv("DSTKEYPATH"); | |
3997081b TL |
99 | if (s) { |
100 | struct stat statbuf; | |
101 | ||
102 | len = strlen(s); | |
103 | if (len > PATH_MAX) { | |
104 | EREPORT(("%s is longer than %d characters, ignoring\n", | |
105 | s, PATH_MAX)); | |
106 | } else if (stat(s, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) { | |
107 | EREPORT(("%s is not a valid directory\n", s)); | |
108 | } else { | |
109 | char *dp = (char *) malloc(len + 2); | |
110 | int l; | |
0da37b4c SR |
111 | if (dp == NULL) { |
112 | EREPORT(("malloc() failed for dp\n")); | |
113 | return; | |
114 | } | |
3997081b TL |
115 | memcpy(dp, s, len + 1); |
116 | l = strlen (dp); | |
117 | if (dp[l - 1] != '/') { | |
118 | dp[l + 1] = 0; | |
119 | dp[l] = '/'; | |
120 | } | |
121 | dst_path = dp; | |
122 | } | |
123 | } | |
124 | memset(dst_t_func, 0, sizeof(dst_t_func)); | |
125 | /* first one is selected */ | |
126 | #if 0 | |
127 | dst_bsafe_init(); | |
128 | dst_rsaref_init(); | |
129 | #endif | |
130 | dst_hmac_md5_init(); | |
131 | #if 0 | |
132 | dst_eay_dss_init(); | |
133 | dst_cylink_init(); | |
134 | #endif | |
135 | } | |
136 | ||
137 | /* | |
138 | * dst_check_algorithm | |
139 | * This function determines if the crypto system for the specified | |
140 | * algorithm is present. | |
141 | * Parameters | |
142 | * alg 1 KEY_RSA | |
143 | * 3 KEY_DSA | |
144 | * 157 KEY_HMAC_MD5 | |
145 | * future algorithms TBD and registered with IANA. | |
146 | * Returns | |
147 | * 1 - The algorithm is available. | |
148 | * 0 - The algorithm is not available. | |
149 | */ | |
150 | int | |
151 | dst_check_algorithm(const int alg) | |
152 | { | |
153 | return (dst_t_func[alg] != NULL); | |
154 | } | |
155 | ||
156 | /* | |
157 | * dst_s_get_key_struct | |
158 | * This function allocates key structure and fills in some of the | |
159 | * fields of the structure. | |
160 | * Parameters: | |
161 | * name: the name of the key | |
162 | * alg: the algorithm number | |
163 | * flags: the dns flags of the key | |
164 | * protocol: the dns protocol of the key | |
165 | * bits: the size of the key | |
166 | * Returns: | |
167 | * NULL if error | |
168 | * valid pointer otherwise | |
169 | */ | |
170 | static DST_KEY * | |
171 | dst_s_get_key_struct(const char *name, const int alg, const u_int32_t flags, | |
172 | const int protocol, const int bits) | |
173 | { | |
174 | DST_KEY *new_key = NULL; | |
175 | ||
176 | if (dst_check_algorithm(alg)) /* make sure alg is available */ | |
177 | new_key = (DST_KEY *) malloc(sizeof(*new_key)); | |
178 | if (new_key == NULL) | |
179 | return (NULL); | |
180 | ||
181 | memset(new_key, 0, sizeof(*new_key)); | |
182 | new_key->dk_key_name = strdup(name); | |
0da37b4c SR |
183 | if (new_key->dk_key_name == NULL) { |
184 | EREPORT(("Unable to duplicate name for key")); | |
185 | free(new_key); | |
186 | return (NULL); | |
187 | } | |
3997081b TL |
188 | new_key->dk_alg = alg; |
189 | new_key->dk_flags = flags; | |
190 | new_key->dk_proto = protocol; | |
191 | new_key->dk_KEY_struct = NULL; | |
192 | new_key->dk_key_size = bits; | |
193 | new_key->dk_func = dst_t_func[alg]; | |
194 | return (new_key); | |
195 | } | |
196 | ||
197 | /* | |
198 | * dst_compare_keys | |
199 | * Compares two keys for equality. | |
200 | * Parameters | |
201 | * key1, key2 Two keys to be compared. | |
202 | * Returns | |
203 | * 0 The keys are equal. | |
204 | * non-zero The keys are not equal. | |
205 | */ | |
206 | ||
207 | int | |
208 | dst_compare_keys(const DST_KEY *key1, const DST_KEY *key2) | |
209 | { | |
210 | if (key1 == key2) | |
211 | return (0); | |
212 | if (key1 == NULL || key2 == NULL) | |
213 | return (4); | |
214 | if (key1->dk_alg != key2->dk_alg) | |
215 | return (1); | |
216 | if (key1->dk_key_size != key2->dk_key_size) | |
217 | return (2); | |
218 | if (key1->dk_id != key2->dk_id) | |
219 | return (3); | |
220 | return (key1->dk_func->compare(key1, key2)); | |
221 | } | |
222 | ||
223 | ||
224 | /* | |
225 | * dst_sign_data | |
226 | * An incremental signing function. Data is signed in steps. | |
227 | * First the context must be initialized (SIG_MODE_INIT). | |
228 | * Then data is hashed (SIG_MODE_UPDATE). Finally the signature | |
229 | * itself is created (SIG_MODE_FINAL). This function can be called | |
230 | * once with INIT, UPDATE and FINAL modes all set, or it can be | |
231 | ||
232 | * called separately with a different mode set for each step. The | |
233 | * UPDATE step can be repeated. | |
234 | * Parameters | |
235 | * mode A bit mask used to specify operation(s) to be performed. | |
236 | * SIG_MODE_INIT 1 Initialize digest | |
237 | * SIG_MODE_UPDATE 2 Add data to digest | |
238 | * SIG_MODE_FINAL 4 Generate signature | |
239 | * from signature | |
240 | * SIG_MODE_ALL (SIG_MODE_INIT,SIG_MODE_UPDATE,SIG_MODE_FINAL | |
241 | * data Data to be signed. | |
242 | * len The length in bytes of data to be signed. | |
243 | * in_key Contains a private key to sign with. | |
244 | * KEY structures should be handled (created, converted, | |
245 | * compared, stored, freed) by the DST. | |
246 | * signature | |
247 | * The location to which the signature will be written. | |
248 | * sig_len Length of the signature field in bytes. | |
249 | * Return | |
20ae1aff | 250 | * 0 Successful INIT or Update operation |
3997081b TL |
251 | * >0 success FINAL (sign) operation |
252 | * <0 failure | |
253 | */ | |
254 | ||
255 | int | |
256 | dst_sign_data(const int mode, DST_KEY *in_key, void **context, | |
257 | const u_char *data, const unsigned len, | |
258 | u_char *signature, const unsigned sig_len) | |
259 | { | |
260 | DUMP(data, mode, len, "dst_sign_data()"); | |
261 | ||
262 | if (mode & SIG_MODE_FINAL && | |
263 | (in_key->dk_KEY_struct == NULL || signature == NULL)) | |
264 | return (MISSING_KEY_OR_SIGNATURE); | |
265 | ||
266 | if (in_key->dk_func && in_key->dk_func->sign) | |
267 | return (in_key->dk_func->sign(mode, in_key, context, data, len, | |
268 | signature, sig_len)); | |
269 | return (UNKNOWN_KEYALG); | |
270 | } | |
271 | ||
272 | ||
273 | /* | |
274 | * dst_verify_data | |
275 | * An incremental verify function. Data is verified in steps. | |
276 | * First the context must be initialized (SIG_MODE_INIT). | |
277 | * Then data is hashed (SIG_MODE_UPDATE). Finally the signature | |
278 | * is verified (SIG_MODE_FINAL). This function can be called | |
279 | * once with INIT, UPDATE and FINAL modes all set, or it can be | |
280 | * called separately with a different mode set for each step. The | |
281 | * UPDATE step can be repeated. | |
282 | * Parameters | |
283 | * mode Operations to perform this time. | |
284 | * SIG_MODE_INIT 1 Initialize digest | |
285 | * SIG_MODE_UPDATE 2 add data to digest | |
286 | * SIG_MODE_FINAL 4 verify signature | |
287 | * SIG_MODE_ALL | |
288 | * (SIG_MODE_INIT,SIG_MODE_UPDATE,SIG_MODE_FINAL) | |
289 | * data Data to pass through the hash function. | |
290 | * len Length of the data in bytes. | |
291 | * in_key Key for verification. | |
292 | * signature Location of signature. | |
293 | * sig_len Length of the signature in bytes. | |
294 | * Returns | |
295 | * 0 Verify success | |
296 | * Non-Zero Verify Failure | |
297 | */ | |
298 | ||
299 | int | |
300 | dst_verify_data(const int mode, DST_KEY *in_key, void **context, | |
301 | const u_char *data, const unsigned len, | |
302 | const u_char *signature, const unsigned sig_len) | |
303 | { | |
304 | DUMP(data, mode, len, "dst_verify_data()"); | |
305 | if (mode & SIG_MODE_FINAL && | |
306 | (in_key->dk_KEY_struct == NULL || signature == NULL)) | |
307 | return (MISSING_KEY_OR_SIGNATURE); | |
308 | ||
309 | if (in_key->dk_func == NULL || in_key->dk_func->verify == NULL) | |
310 | return (UNSUPPORTED_KEYALG); | |
311 | return (in_key->dk_func->verify(mode, in_key, context, data, len, | |
312 | signature, sig_len)); | |
313 | } | |
314 | ||
315 | ||
316 | /* | |
317 | * dst_read_private_key | |
318 | * Access a private key. First the list of private keys that have | |
319 | * already been read in is searched, then the key accessed on disk. | |
320 | * If the private key can be found, it is returned. If the key cannot | |
321 | * be found, a null pointer is returned. The options specify required | |
322 | * key characteristics. If the private key requested does not have | |
323 | * these characteristics, it will not be read. | |
324 | * Parameters | |
325 | * in_keyname The private key name. | |
326 | * in_id The id of the private key. | |
327 | * options DST_FORCE_READ Read from disk - don't use a previously | |
328 | * read key. | |
20ae1aff FD |
329 | * DST_CAN_SIGN The key must be usable for signing. |
330 | * DST_NO_AUTHEN The key must be usable for authentication. | |
3997081b TL |
331 | * DST_STANDARD Return any key |
332 | * Returns | |
333 | * NULL If there is no key found in the current directory or | |
334 | * this key has not been loaded before. | |
335 | * !NULL Success - KEY structure returned. | |
336 | */ | |
337 | ||
338 | DST_KEY * | |
339 | dst_read_key(const char *in_keyname, const unsigned in_id, | |
340 | const int in_alg, const int type) | |
341 | { | |
3997081b TL |
342 | DST_KEY *dg_key = NULL, *pubkey = NULL; |
343 | ||
344 | if (!dst_check_algorithm(in_alg)) { /* make sure alg is available */ | |
20ae1aff | 345 | EREPORT(("dst_read_private_key(): Algorithm %d not supported\n", |
3997081b TL |
346 | in_alg)); |
347 | return (NULL); | |
348 | } | |
bb9189c3 | 349 | if ((type & (DST_PUBLIC | DST_PRIVATE)) == 0) |
3997081b TL |
350 | return (NULL); |
351 | if (in_keyname == NULL) { | |
352 | EREPORT(("dst_read_private_key(): Null key name passed in\n")); | |
353 | return (NULL); | |
36e2c224 | 354 | } |
3997081b TL |
355 | |
356 | /* before I read in the public key, check if it is allowed to sign */ | |
36e2c224 | 357 | if ((pubkey = dst_s_read_public_key(in_keyname, in_id, in_alg)) == NULL) |
3997081b TL |
358 | return (NULL); |
359 | ||
360 | if (type == DST_PUBLIC) | |
361 | return pubkey; | |
362 | ||
36e2c224 | 363 | if (!(dg_key = dst_s_get_key_struct(in_keyname, pubkey->dk_alg, |
3997081b TL |
364 | pubkey->dk_flags, pubkey->dk_proto, |
365 | 0))) | |
366 | return (dg_key); | |
367 | /* Fill in private key and some fields in the general key structure */ | |
36e2c224 | 368 | if (dst_s_read_private_key_file((char *)(in_keyname), dg_key, pubkey->dk_id, |
3997081b TL |
369 | pubkey->dk_alg) == 0) |
370 | dg_key = dst_free_key(dg_key); | |
371 | ||
dc9d7b08 | 372 | (void) dst_free_key(pubkey); |
3997081b TL |
373 | return (dg_key); |
374 | } | |
375 | ||
376 | int | |
377 | dst_write_key(const DST_KEY *key, const int type) | |
378 | { | |
379 | int pub = 0, priv = 0; | |
380 | ||
381 | if (key == NULL) | |
382 | return (0); | |
383 | if (!dst_check_algorithm(key->dk_alg)) { /* make sure alg is available */ | |
20ae1aff | 384 | EREPORT(("dst_write_key(): Algorithm %d not supported\n", |
3997081b TL |
385 | key->dk_alg)); |
386 | return (UNSUPPORTED_KEYALG); | |
387 | } | |
388 | if ((type & (DST_PRIVATE|DST_PUBLIC)) == 0) | |
389 | return (0); | |
390 | ||
391 | if (type & DST_PUBLIC) | |
392 | if ((pub = dst_s_write_public_key(key)) < 0) | |
393 | return (pub); | |
394 | if (type & DST_PRIVATE) | |
395 | if ((priv = dst_s_write_private_key(key)) < 0) | |
396 | return (priv); | |
397 | return (priv+pub); | |
398 | } | |
399 | ||
400 | /* | |
401 | * dst_write_private_key | |
402 | * Write a private key to disk. The filename will be of the form: | |
403 | * K<key->dk_name>+<key->dk_alg>+<key->dk_id>.<private key suffix>. | |
404 | * If there is already a file with this name, an error is returned. | |
405 | * | |
36e2c224 | 406 | * |
3997081b TL |
407 | * Parameters |
408 | * key A DST managed key structure that contains | |
409 | * all information needed about a key. | |
410 | * Return | |
411 | * >= 0 Correct behavior. Returns length of encoded key value | |
412 | * written to disk. | |
413 | * < 0 error. | |
414 | */ | |
415 | ||
416 | static int | |
417 | dst_s_write_private_key(const DST_KEY *key) | |
418 | { | |
419 | u_char encoded_block[RAW_KEY_SIZE]; | |
420 | char file[PATH_MAX]; | |
421 | unsigned len; | |
422 | FILE *fp; | |
423 | ||
424 | /* First encode the key into the portable key format */ | |
425 | if (key == NULL) | |
426 | return (-1); | |
427 | if (key->dk_KEY_struct == NULL) | |
428 | return (0); /* null key has no private key */ | |
429 | ||
430 | if (key->dk_func == NULL || key->dk_func->to_file_fmt == NULL) { | |
431 | EREPORT(("dst_write_private_key(): Unsupported operation %d\n", | |
432 | key->dk_alg)); | |
433 | return (-5); | |
434 | } else if ((len = key->dk_func->to_file_fmt(key, (char *)encoded_block, | |
435 | sizeof(encoded_block))) <= 0) { | |
436 | EREPORT(("dst_write_private_key(): Failed encoding private RSA bsafe key %d\n", len)); | |
437 | return (-8); | |
438 | } | |
439 | /* Now I can create the file I want to use */ | |
440 | dst_s_build_filename(file, key->dk_key_name, key->dk_id, key->dk_alg, | |
441 | PRIVATE_KEY, PATH_MAX); | |
442 | ||
443 | /* Do not overwrite an existing file */ | |
444 | if ((fp = dst_s_fopen(file, "w", 0600)) != NULL) { | |
445 | int nn; | |
446 | if ((nn = fwrite(encoded_block, 1, len, fp)) != len) { | |
447 | EREPORT(("dst_write_private_key(): Write failure on %s %d != %d errno=%d\n", | |
448 | file, out_len, nn, errno)); | |
0f750c4f | 449 | fclose(fp); |
3997081b TL |
450 | return (-5); |
451 | } | |
452 | fclose(fp); | |
453 | } else { | |
454 | EREPORT(("dst_write_private_key(): Can not create file %s\n" | |
455 | ,file)); | |
456 | return (-6); | |
457 | } | |
458 | memset(encoded_block, 0, len); | |
459 | return (len); | |
460 | } | |
461 | ||
462 | /* | |
463 | * | |
464 | * dst_read_public_key | |
465 | * Read a public key from disk and store in a DST key structure. | |
466 | * Parameters | |
467 | * in_name K<in_name><in_id>.<public key suffix> is the | |
468 | * filename of the key file to be read. | |
469 | * Returns | |
470 | * NULL If the key does not exist or no name is supplied. | |
20ae1aff | 471 | * NON-NULL Initialized key structure if the key exists. |
3997081b TL |
472 | */ |
473 | ||
474 | static DST_KEY * | |
475 | dst_s_read_public_key(const char *in_name, const unsigned in_id, int in_alg) | |
476 | { | |
477 | unsigned flags, len; | |
478 | int proto, alg, dlen; | |
479 | int c; | |
804401cc EH |
480 | char name[PATH_MAX], enckey[RAW_KEY_SIZE]; |
481 | unsigned char *notspace; | |
3997081b TL |
482 | u_char deckey[RAW_KEY_SIZE]; |
483 | FILE *fp; | |
36e2c224 | 484 | DST_KEY *pubkey = NULL; |
3997081b TL |
485 | |
486 | if (in_name == NULL) { | |
487 | EREPORT(("dst_read_public_key(): No key name given\n")); | |
488 | return (NULL); | |
489 | } | |
490 | if (dst_s_build_filename(name, in_name, in_id, in_alg, PUBLIC_KEY, | |
491 | PATH_MAX) == -1) { | |
492 | EREPORT(("dst_read_public_key(): Cannot make filename from %s, %d, and %s\n", | |
493 | in_name, in_id, PUBLIC_KEY)); | |
494 | return (NULL); | |
495 | } | |
496 | /* | |
497 | * Open the file and read it's formatted contents up to key | |
498 | * File format: | |
499 | * domain.name [ttl] [IN] KEY <flags> <protocol> <algorithm> <key> | |
500 | * flags, proto, alg stored as decimal (or hex numbers FIXME). | |
501 | * (FIXME: handle parentheses for line continuation.) | |
502 | */ | |
503 | if ((fp = dst_s_fopen(name, "r", 0)) == NULL) { | |
504 | EREPORT(("dst_read_public_key(): Public Key not found %s\n", | |
505 | name)); | |
506 | return (NULL); | |
507 | } | |
508 | /* Skip domain name, which ends at first blank */ | |
509 | while ((c = getc(fp)) != EOF) | |
510 | if (isspace(c)) | |
511 | break; | |
512 | /* Skip blank to get to next field */ | |
513 | while ((c = getc(fp)) != EOF) | |
514 | if (!isspace(c)) | |
515 | break; | |
516 | ||
517 | /* Skip optional TTL -- if initial digit, skip whole word. */ | |
518 | if (isdigit(c)) { | |
519 | while ((c = getc(fp)) != EOF) | |
520 | if (isspace(c)) | |
521 | break; | |
522 | while ((c = getc(fp)) != EOF) | |
523 | if (!isspace(c)) | |
524 | break; | |
525 | } | |
526 | /* Skip optional "IN" */ | |
527 | if (c == 'I' || c == 'i') { | |
528 | while ((c = getc(fp)) != EOF) | |
529 | if (isspace(c)) | |
530 | break; | |
531 | while ((c = getc(fp)) != EOF) | |
532 | if (!isspace(c)) | |
533 | break; | |
534 | } | |
535 | /* Locate and skip "KEY" */ | |
536 | if (c != 'K' && c != 'k') { | |
537 | EREPORT(("\"KEY\" doesn't appear in file: %s", name)); | |
538 | return NULL; | |
539 | } | |
540 | while ((c = getc(fp)) != EOF) | |
541 | if (isspace(c)) | |
542 | break; | |
543 | while ((c = getc(fp)) != EOF) | |
544 | if (!isspace(c)) | |
545 | break; | |
20ae1aff | 546 | ungetc(c, fp); /* return the character to the input field */ |
3997081b TL |
547 | /* Handle hex!! FIXME. */ |
548 | ||
549 | if (fscanf(fp, "%d %d %d", &flags, &proto, &alg) != 3) { | |
550 | EREPORT(("dst_read_public_key(): Can not read flag/proto/alg field from %s\n" | |
551 | ,name)); | |
552 | return (NULL); | |
553 | } | |
554 | /* read in the key string */ | |
ae566556 SR |
555 | if ((fgets(enckey, sizeof(enckey), fp) == NULL) && |
556 | (ferror(fp) != 0)) { | |
557 | EREPORT(("dst_read_public_kety(): Error reading key\n")); | |
558 | return (NULL); | |
559 | } | |
3997081b TL |
560 | |
561 | /* If we aren't at end-of-file, something is wrong. */ | |
562 | while ((c = getc(fp)) != EOF) | |
563 | if (!isspace(c)) | |
564 | break; | |
565 | if (!feof(fp)) { | |
566 | EREPORT(("Key too long in file: %s", name)); | |
567 | return NULL; | |
568 | } | |
569 | fclose(fp); | |
570 | ||
571 | if ((len = strlen(enckey)) <= 0) | |
572 | return (NULL); | |
573 | ||
574 | /* discard \n */ | |
575 | enckey[--len] = '\0'; | |
576 | ||
577 | /* remove leading spaces */ | |
28868515 | 578 | for (notspace = (unsigned char *)enckey; isspace(*notspace); len--) |
3997081b TL |
579 | notspace++; |
580 | ||
28868515 | 581 | dlen = b64_pton((char *)notspace, deckey, sizeof(deckey)); |
3997081b TL |
582 | if (dlen < 0) { |
583 | EREPORT(("dst_read_public_key: bad return from b64_pton = %d", | |
584 | dlen)); | |
585 | return (NULL); | |
586 | } | |
36e2c224 | 587 | |
3997081b | 588 | /* store key and info in a key structure that is returned */ |
36e2c224 TM |
589 | /* Set the key id after we create because somehow this got missed. */ |
590 | pubkey = dst_buffer_to_key(in_name, alg, flags, proto, | |
591 | deckey, (unsigned)dlen); | |
592 | if (pubkey) { | |
593 | pubkey->dk_id = in_id; | |
594 | } | |
595 | ||
596 | return (pubkey); | |
3997081b TL |
597 | } |
598 | ||
599 | ||
600 | /* | |
601 | * dst_write_public_key | |
602 | * Write a key to disk in DNS format. | |
603 | * Parameters | |
604 | * key Pointer to a DST key structure. | |
605 | * Returns | |
606 | * 0 Failure | |
607 | * 1 Success | |
608 | */ | |
609 | ||
610 | static int | |
611 | dst_s_write_public_key(const DST_KEY *key) | |
612 | { | |
613 | FILE *fp; | |
614 | char filename[PATH_MAX]; | |
615 | u_char out_key[RAW_KEY_SIZE]; | |
616 | char enc_key[RAW_KEY_SIZE]; | |
617 | int len = 0; | |
618 | ||
619 | memset(out_key, 0, sizeof(out_key)); | |
620 | if (key == NULL) { | |
621 | EREPORT(("dst_write_public_key(): No key specified \n")); | |
622 | return (0); | |
623 | } else if ((len = dst_key_to_dnskey(key, out_key, sizeof(out_key)))< 0) | |
624 | return (0); | |
625 | ||
626 | /* Make the filename */ | |
627 | if (dst_s_build_filename(filename, key->dk_key_name, key->dk_id, | |
628 | key->dk_alg, PUBLIC_KEY, PATH_MAX) == -1) { | |
629 | EREPORT(("dst_write_public_key(): Cannot make filename from %s, %d, and %s\n", | |
630 | key->dk_key_name, key->dk_id, PUBLIC_KEY)); | |
631 | return (0); | |
632 | } | |
633 | /* create public key file */ | |
634 | if ((fp = dst_s_fopen(filename, "w+", 0644)) == NULL) { | |
635 | EREPORT(("DST_write_public_key: open of file:%s failed (errno=%d)\n", | |
636 | filename, errno)); | |
637 | return (0); | |
638 | } | |
639 | /*write out key first base64 the key data */ | |
640 | if (key->dk_flags & DST_EXTEND_FLAG) | |
641 | b64_ntop(&out_key[6], | |
642 | (unsigned)(len - 6), enc_key, sizeof(enc_key)); | |
643 | else | |
644 | b64_ntop(&out_key[4], | |
645 | (unsigned)(len - 4), enc_key, sizeof(enc_key)); | |
646 | fprintf(fp, "%s IN KEY %d %d %d %s\n", | |
647 | key->dk_key_name, | |
648 | key->dk_flags, key->dk_proto, key->dk_alg, enc_key); | |
649 | fclose(fp); | |
650 | return (1); | |
651 | } | |
652 | ||
653 | ||
654 | /* | |
655 | * dst_dnskey_to_public_key | |
656 | * This function converts the contents of a DNS KEY RR into a DST | |
657 | * key structure. | |
20ae1aff | 658 | * Parameters |
3997081b TL |
659 | * len Length of the RDATA of the KEY RR RDATA |
660 | * rdata A pointer to the the KEY RR RDATA. | |
661 | * in_name Key name to be stored in key structure. | |
662 | * Returns | |
663 | * NULL Failure | |
664 | * NON-NULL Success. Pointer to key structure. | |
665 | * Caller's responsibility to free() it. | |
666 | */ | |
667 | ||
668 | DST_KEY * | |
669 | dst_dnskey_to_key(const char *in_name, | |
670 | const u_char *rdata, const unsigned len) | |
671 | { | |
672 | DST_KEY *key_st; | |
673 | int alg ; | |
674 | int start = DST_KEY_START; | |
675 | ||
0f750c4f | 676 | if (in_name == NULL || rdata == NULL || len <= DST_KEY_ALG) /* no data */ |
3997081b TL |
677 | return (NULL); |
678 | alg = (u_int8_t) rdata[DST_KEY_ALG]; | |
679 | if (!dst_check_algorithm(alg)) { /* make sure alg is available */ | |
20ae1aff | 680 | EREPORT(("dst_dnskey_to_key(): Algorithm %d not supported\n", |
3997081b TL |
681 | alg)); |
682 | return (NULL); | |
683 | } | |
684 | if ((key_st = dst_s_get_key_struct(in_name, alg, 0, 0, 0)) == NULL) | |
685 | return (NULL); | |
686 | ||
3997081b TL |
687 | key_st->dk_flags = dst_s_get_int16(rdata); |
688 | key_st->dk_proto = (u_int16_t) rdata[DST_KEY_PROT]; | |
689 | if (key_st->dk_flags & DST_EXTEND_FLAG) { | |
690 | u_int32_t ext_flags; | |
691 | ext_flags = (u_int32_t) dst_s_get_int16(&rdata[DST_EXT_FLAG]); | |
692 | key_st->dk_flags = key_st->dk_flags | (ext_flags << 16); | |
693 | start += 2; | |
694 | } | |
695 | /* | |
20ae1aff | 696 | * now point to the beginning of the data representing the encoding |
3997081b TL |
697 | * of the key |
698 | */ | |
699 | if (key_st->dk_func && key_st->dk_func->from_dns_key) { | |
700 | if (key_st->dk_func->from_dns_key(key_st, &rdata[start], | |
701 | len - start) > 0) | |
702 | return (key_st); | |
703 | } else | |
20ae1aff | 704 | EREPORT(("dst_dnskey_to_public_key(): unsupported alg %d\n", |
3997081b TL |
705 | alg)); |
706 | ||
707 | SAFE_FREE(key_st); | |
708 | return (key_st); | |
709 | } | |
710 | ||
711 | ||
712 | /* | |
713 | * dst_public_key_to_dnskey | |
714 | * Function to encode a public key into DNS KEY wire format | |
715 | * Parameters | |
716 | * key Key structure to encode. | |
717 | * out_storage Location to write the encoded key to. | |
718 | * out_len Size of the output array. | |
719 | * Returns | |
720 | * <0 Failure | |
721 | * >=0 Number of bytes written to out_storage | |
722 | */ | |
723 | ||
724 | int | |
725 | dst_key_to_dnskey(const DST_KEY *key, u_char *out_storage, | |
726 | const unsigned out_len) | |
727 | { | |
728 | u_int16_t val; | |
729 | int loc = 0; | |
730 | int enc_len = 0; | |
731 | if (key == NULL) | |
732 | return (-1); | |
733 | ||
734 | if (!dst_check_algorithm(key->dk_alg)) { /* make sure alg is available */ | |
20ae1aff | 735 | EREPORT(("dst_key_to_dnskey(): Algorithm %d not supported\n", |
3997081b TL |
736 | key->dk_alg)); |
737 | return (UNSUPPORTED_KEYALG); | |
738 | } | |
739 | memset(out_storage, 0, out_len); | |
740 | val = (u_int16_t)(key->dk_flags & 0xffff); | |
49146f3c DN |
741 | out_storage[0] = (val >> 8) & 0xff; |
742 | out_storage[1] = val & 0xff; | |
3997081b TL |
743 | loc += 2; |
744 | ||
745 | out_storage[loc++] = (u_char) key->dk_proto; | |
746 | out_storage[loc++] = (u_char) key->dk_alg; | |
747 | ||
748 | if (key->dk_flags > 0xffff) { /* Extended flags */ | |
749 | val = (u_int16_t)((key->dk_flags >> 16) & 0xffff); | |
49146f3c DN |
750 | out_storage[loc] = (val >> 8) & 0xff; |
751 | out_storage[loc+1] = val & 0xff; | |
3997081b TL |
752 | loc += 2; |
753 | } | |
754 | if (key->dk_KEY_struct == NULL) | |
755 | return (loc); | |
756 | if (key->dk_func && key->dk_func->to_dns_key) { | |
757 | enc_len = key->dk_func->to_dns_key(key, | |
758 | (u_char *) &out_storage[loc], | |
759 | out_len - loc); | |
760 | if (enc_len > 0) | |
761 | return (enc_len + loc); | |
762 | else | |
763 | return (-1); | |
764 | } else | |
765 | EREPORT(("dst_key_to_dnskey(): Unsupported ALG %d\n", | |
766 | key->dk_alg)); | |
767 | return (-1); | |
768 | } | |
769 | ||
770 | ||
771 | /* | |
772 | * dst_buffer_to_key | |
773 | * Function to encode a string of raw data into a DST key | |
774 | * Parameters | |
775 | * alg The algorithm (HMAC only) | |
776 | * key A pointer to the data | |
777 | * keylen The length of the data | |
778 | * Returns | |
779 | * NULL an error occurred | |
780 | * NON-NULL the DST key | |
781 | */ | |
782 | DST_KEY * | |
783 | dst_buffer_to_key(const char *key_name, /* name of the key */ | |
784 | const int alg, /* algorithm */ | |
785 | const unsigned flags, /* dns flags */ | |
786 | const int protocol, /* dns protocol */ | |
787 | const u_char *key_buf, /* key in dns wire fmt */ | |
788 | const unsigned key_len) /* size of key */ | |
789 | { | |
790 | ||
791 | DST_KEY *dkey = NULL; | |
792 | ||
793 | if (!dst_check_algorithm(alg)) { /* make sure alg is available */ | |
20ae1aff | 794 | EREPORT(("dst_buffer_to_key(): Algorithm %d not supported\n", alg)); |
3997081b TL |
795 | return (NULL); |
796 | } | |
797 | ||
798 | dkey = dst_s_get_key_struct(key_name, alg, flags, protocol, -1); | |
799 | ||
800 | if (dkey == NULL) | |
801 | return (NULL); | |
802 | if (dkey->dk_func != NULL && | |
803 | dkey->dk_func->from_dns_key != NULL) { | |
804 | if (dkey->dk_func->from_dns_key(dkey, key_buf, key_len) < 0) { | |
805 | EREPORT(("dst_buffer_to_key(): dst_buffer_to_hmac failed\n")); | |
0f750c4f SR |
806 | (void) (dst_free_key(dkey)); |
807 | return (NULL); | |
3997081b TL |
808 | } |
809 | return (dkey); | |
810 | } | |
0f750c4f | 811 | (void) (dst_free_key(dkey)); |
3997081b TL |
812 | return (NULL); |
813 | } | |
814 | ||
815 | int | |
816 | dst_key_to_buffer(DST_KEY *key, u_char *out_buff, unsigned buf_len) | |
817 | { | |
818 | int len; | |
20ae1aff | 819 | /* this function will extract the secret of HMAC into a buffer */ |
3997081b TL |
820 | if(key == NULL) |
821 | return (0); | |
a07d99bb | 822 | if(key->dk_func != NULL && key->dk_func->to_dns_key != NULL) { |
3997081b TL |
823 | len = key->dk_func->to_dns_key(key, out_buff, buf_len); |
824 | if (len < 0) | |
825 | return (0); | |
826 | return (len); | |
827 | } | |
828 | return (0); | |
829 | } | |
830 | ||
831 | ||
832 | /* | |
833 | * dst_s_read_private_key_file | |
834 | * Function reads in private key from a file. | |
835 | * Fills out the KEY structure. | |
836 | * Parameters | |
837 | * name Name of the key to be read. | |
838 | * pk_key Structure that the key is returned in. | |
839 | * in_id Key identifier (tag) | |
840 | * Return | |
20ae1aff | 841 | * 1 if everything works |
3997081b TL |
842 | * 0 if there is any problem |
843 | */ | |
844 | ||
845 | static int | |
846 | dst_s_read_private_key_file(char *name, DST_KEY *pk_key, unsigned in_id, | |
847 | int in_alg) | |
848 | { | |
849 | int cnt, alg, len, major, minor, file_major, file_minor; | |
850 | int id; | |
851 | char filename[PATH_MAX]; | |
36e2c224 | 852 | u_char in_buff[RAW_KEY_SIZE + 1]; |
06eb8bab | 853 | char *p; |
3997081b TL |
854 | FILE *fp; |
855 | ||
856 | if (name == NULL || pk_key == NULL) { | |
857 | EREPORT(("dst_read_private_key_file(): No key name given\n")); | |
858 | return (0); | |
859 | } | |
860 | /* Make the filename */ | |
861 | if (dst_s_build_filename(filename, name, in_id, in_alg, PRIVATE_KEY, | |
862 | PATH_MAX) == -1) { | |
863 | EREPORT(("dst_read_private_key(): Cannot make filename from %s, %d, and %s\n", | |
864 | name, in_id, PRIVATE_KEY)); | |
865 | return (0); | |
866 | } | |
867 | /* first check if we can find the key file */ | |
868 | if ((fp = dst_s_fopen(filename, "r", 0)) == NULL) { | |
869 | EREPORT(("dst_s_read_private_key_file: Could not open file %s in directory %s\n", | |
870 | filename, dst_path[0] ? dst_path : | |
871 | (char *) getcwd(NULL, PATH_MAX - 1))); | |
872 | return (0); | |
873 | } | |
36e2c224 | 874 | |
3997081b | 875 | /* now read the header info from the file */ |
36e2c224 | 876 | if ((cnt = fread(in_buff, 1, sizeof(in_buff) - 1, fp)) < 5) { |
3997081b TL |
877 | fclose(fp); |
878 | EREPORT(("dst_s_read_private_key_file: error reading file %s (empty file)\n", | |
879 | filename)); | |
880 | return (0); | |
881 | } | |
882 | /* decrypt key */ | |
883 | fclose(fp); | |
36e2c224 TM |
884 | in_buff[cnt] = '\0'; |
885 | ||
3997081b TL |
886 | if (memcmp(in_buff, "Private-key-format: v", 20) != 0) |
887 | goto fail; | |
888 | len = cnt; | |
06eb8bab | 889 | p = (char *)in_buff; |
3997081b TL |
890 | |
891 | if (!dst_s_verify_str((const char **) &p, "Private-key-format: v")) { | |
892 | EREPORT(("dst_s_read_private_key_file(): Not a Key file/Decrypt failed %s\n", name)); | |
893 | goto fail; | |
894 | } | |
895 | /* read in file format */ | |
06eb8bab | 896 | sscanf(p, "%d.%d", &file_major, &file_minor); |
3997081b TL |
897 | sscanf(KEY_FILE_FORMAT, "%d.%d", &major, &minor); |
898 | if (file_major < 1) { | |
899 | EREPORT(("dst_s_read_private_key_file(): Unknown keyfile %d.%d version for %s\n", | |
900 | file_major, file_minor, name)); | |
901 | goto fail; | |
902 | } else if (file_major > major || file_minor > minor) | |
903 | EREPORT(( | |
904 | "dst_s_read_private_key_file(): Keyfile %s version higher than mine %d.%d MAY FAIL\n", | |
905 | name, file_major, file_minor)); | |
906 | ||
907 | while (*p++ != '\n') ; /* skip to end of line */ | |
908 | ||
909 | if (!dst_s_verify_str((const char **) &p, "Algorithm: ")) | |
910 | goto fail; | |
911 | ||
06eb8bab | 912 | if (sscanf(p, "%d", &alg) != 1) |
3997081b TL |
913 | goto fail; |
914 | while (*p++ != '\n') ; /* skip to end of line */ | |
915 | ||
916 | if (pk_key->dk_key_name && !strcmp(pk_key->dk_key_name, name)) | |
917 | SAFE_FREE2(pk_key->dk_key_name, strlen(pk_key->dk_key_name)); | |
918 | pk_key->dk_key_name = (char *) strdup(name); | |
0da37b4c SR |
919 | if (pk_key->dk_key_name == NULL) { |
920 | EREPORT(("Unable to duplicate name for key")); | |
921 | goto fail; | |
922 | } | |
3997081b TL |
923 | |
924 | /* allocate and fill in key structure */ | |
925 | if (pk_key->dk_func == NULL || pk_key->dk_func->from_file_fmt == NULL) | |
926 | goto fail; | |
927 | ||
928 | id = pk_key->dk_func->from_file_fmt(pk_key, (char *)p, | |
06eb8bab | 929 | (unsigned)(&in_buff[len] - (u_char *)p)); |
3997081b TL |
930 | if (id < 0) |
931 | goto fail; | |
932 | ||
933 | /* Make sure the actual key tag matches the input tag used in the filename | |
934 | */ | |
935 | if (id != in_id) { | |
936 | EREPORT(("dst_s_read_private_key_file(): actual tag of key read %d != input tag used to build filename %d.\n", id, in_id)); | |
937 | goto fail; | |
938 | } | |
939 | pk_key->dk_id = (u_int16_t) id; | |
940 | pk_key->dk_alg = alg; | |
941 | memset(in_buff, 0, (unsigned)cnt); | |
942 | return (1); | |
943 | ||
944 | fail: | |
945 | memset(in_buff, 0, (unsigned)cnt); | |
946 | return (0); | |
947 | } | |
948 | ||
949 | ||
950 | /* | |
951 | * dst_generate_key | |
952 | * Generate and store a public/private keypair. | |
953 | * Keys will be stored in formatted files. | |
954 | * Parameters | |
955 | * name Name of the new key. Used to create key files | |
956 | * K<name>+<alg>+<id>.public and K<name>+<alg>+<id>.private. | |
957 | * bits Size of the new key in bits. | |
958 | * exp What exponent to use: | |
959 | * 0 use exponent 3 | |
960 | * non-zero use Fermant4 | |
961 | * flags The default value of the DNS Key flags. | |
962 | * The DNS Key RR Flag field is defined in RFC 2065, | |
963 | * section 3.3. The field has 16 bits. | |
964 | * protocol | |
965 | * Default value of the DNS Key protocol field. | |
966 | * The DNS Key protocol field is defined in RFC 2065, | |
967 | * section 3.4. The field has 8 bits. | |
968 | * alg What algorithm to use. Currently defined: | |
969 | * KEY_RSA 1 | |
970 | * KEY_DSA 3 | |
971 | * KEY_HMAC 157 | |
972 | * out_id The key tag is returned. | |
973 | * | |
974 | * Return | |
975 | * NULL Failure | |
976 | * non-NULL the generated key pair | |
977 | * Caller frees the result, and its dk_name pointer. | |
978 | */ | |
979 | DST_KEY * | |
980 | dst_generate_key(const char *name, const int bits, const int exp, | |
981 | const unsigned flags, const int protocol, const int alg) | |
982 | { | |
983 | DST_KEY *new_key = NULL; | |
984 | int res; | |
985 | if (name == NULL) | |
986 | return (NULL); | |
987 | ||
988 | if (!dst_check_algorithm(alg)) { /* make sure alg is available */ | |
20ae1aff | 989 | EREPORT(("dst_generate_key(): Algorithm %d not supported\n", alg)); |
3997081b TL |
990 | return (NULL); |
991 | } | |
992 | ||
993 | new_key = dst_s_get_key_struct(name, alg, flags, protocol, bits); | |
994 | if (new_key == NULL) | |
995 | return (NULL); | |
996 | if (bits == 0) /* null key we are done */ | |
997 | return (new_key); | |
998 | if (new_key->dk_func == NULL || new_key->dk_func->generate == NULL) { | |
999 | EREPORT(("dst_generate_key_pair():Unsupported algorithm %d\n", | |
1000 | alg)); | |
1001 | return (dst_free_key(new_key)); | |
1002 | } | |
1003 | if ((res = new_key->dk_func->generate(new_key, exp)) <= 0) { | |
1004 | EREPORT(("dst_generate_key_pair(): Key generation failure %s %d %d %d\n", | |
1005 | new_key->dk_key_name, new_key->dk_alg, | |
1006 | new_key->dk_key_size, exp)); | |
1007 | return (dst_free_key(new_key)); | |
1008 | } | |
1009 | return (new_key); | |
1010 | } | |
1011 | ||
1012 | ||
1013 | /* | |
1014 | * dst_free_key | |
1015 | * Release all data structures pointed to by a key structure. | |
1016 | * Parameters | |
1017 | * f_key Key structure to be freed. | |
1018 | */ | |
1019 | ||
1020 | DST_KEY * | |
1021 | dst_free_key(DST_KEY *f_key) | |
1022 | { | |
1023 | ||
1024 | if (f_key == NULL) | |
1025 | return (f_key); | |
1026 | if (f_key->dk_func && f_key->dk_func->destroy) | |
1027 | f_key->dk_KEY_struct = | |
1028 | f_key->dk_func->destroy(f_key->dk_KEY_struct); | |
1029 | else { | |
1030 | EREPORT(("dst_free_key(): Unknown key alg %d\n", | |
1031 | f_key->dk_alg)); | |
3997081b TL |
1032 | } |
1033 | if (f_key->dk_KEY_struct) { | |
df1280d0 SR |
1034 | /* |
1035 | * We can't used SAFE_FREE* here as we do not know the size | |
1036 | * of the structure, so no way to zero it. | |
1037 | */ | |
1038 | free(f_key->dk_KEY_struct); | |
1039 | f_key->dk_KEY_struct = NULL; | |
3997081b TL |
1040 | } |
1041 | if (f_key->dk_key_name) | |
1042 | SAFE_FREE(f_key->dk_key_name); | |
1043 | SAFE_FREE(f_key); | |
1044 | return (NULL); | |
1045 | } | |
1046 | ||
1047 | /* | |
1048 | * dst_sig_size | |
20ae1aff | 1049 | * Return the maximum size of signature from the key specified in bytes |
3997081b TL |
1050 | * Parameters |
1051 | * key | |
1052 | * Returns | |
1053 | * bytes | |
1054 | */ | |
1055 | int | |
1056 | dst_sig_size(DST_KEY *key) { | |
1057 | switch (key->dk_alg) { | |
1058 | case KEY_HMAC_MD5: | |
1059 | return (16); | |
1060 | case KEY_HMAC_SHA1: | |
1061 | return (20); | |
1062 | case KEY_RSA: | |
1063 | return (key->dk_key_size + 7) / 8; | |
1064 | case KEY_DSA: | |
1065 | return (40); | |
1066 | default: | |
1067 | EREPORT(("dst_sig_size(): Unknown key alg %d\n", key->dk_alg)); | |
1068 | return -1; | |
1069 | } | |
1070 | } | |
1071 | ||
1072 | /* | |
1073 | * dst_random | |
1074 | * function that multiplexes number of random number generators | |
1075 | * Parameters | |
1076 | * mode: select the random number generator | |
1077 | * wanted is how many bytes of random data are requested | |
1078 | * outran is a buffer of size at least wanted for the output data | |
1079 | * | |
1080 | * Returns | |
1081 | * number of bytes written to outran | |
1082 | */ | |
1083 | int | |
1084 | dst_random(const int mode, unsigned wanted, u_char *outran) | |
1085 | { | |
36e2c224 | 1086 | if (wanted <= 0 || outran == NULL) |
3997081b TL |
1087 | return (0); |
1088 | ||
1089 | switch (mode) { | |
36e2c224 TM |
1090 | case DST_RAND_SEMI: { |
1091 | u_int32_t *op = (u_int32_t *)outran; | |
1092 | int i; | |
1093 | for (i = 0; i < wanted; i+= sizeof(u_int32_t), op++) { | |
1094 | *op = dst_s_quick_random(i); | |
3997081b | 1095 | } |
36e2c224 | 1096 | |
3997081b | 1097 | return (wanted); |
36e2c224 | 1098 | } |
3997081b TL |
1099 | case DST_RAND_STD: |
1100 | return (dst_s_semi_random(outran, wanted)); | |
1101 | case DST_RAND_KEY: | |
1102 | return (dst_s_random(outran, wanted)); | |
1103 | case DST_RAND_DSS: | |
1104 | default: | |
1105 | /* need error case here XXX OG */ | |
1106 | return (0); | |
1107 | } | |
1108 | } |