2 * Copyright (c) 2009 The NetBSD Foundation, Inc.
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Alistair Crooks (agc@NetBSD.org)
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
31 #ifdef HAVE_SYS_CDEFS_H
32 #include <sys/cdefs.h>
35 #include <sys/types.h>
37 #include <sys/param.h>
39 #include <arpa/inet.h>
55 #ifdef HAVE_OPENSSL_CAST_H
56 #include <openssl/cast.h>
59 #include <openssl/pem.h>
62 #include "fastctype.h"
64 #include "packet-parse.h"
65 #include "netpgpdefs.h"
66 #include "netpgpsdk.h"
68 #include "netpgpdigest.h"
71 /* structure for earching for constant strings */
72 typedef struct str_t
{
73 const char *s
; /* string */
74 size_t len
; /* its length */
75 int type
; /* return type */
79 #define USE_ARG(x) /*LINTED*/(void)&x
82 static const uint8_t base64s
[] =
83 /* 000 */ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
84 /* 016 */ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
85 /* 032 */ "\0\0\0\0\0\0\0\0\0\0\0?\0\0\0@"
86 /* 048 */ "56789:;<=>\0\0\0\0\0\0"
87 /* 064 */ "\0\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17"
88 /* 080 */ "\20\21\22\23\24\25\26\27\30\31\32\0\0\0\0\0"
89 /* 096 */ "\0\33\34\35\36\37 !\"#$%&'()"
90 /* 112 */ "*+,-./01234\0\0\0\0\0"
91 /* 128 */ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
92 /* 144 */ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
93 /* 160 */ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
94 /* 176 */ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
95 /* 192 */ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
96 /* 208 */ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
97 /* 224 */ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
98 /* 240 */ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
101 /* short function to decode from base64 */
102 /* inspired by an ancient copy of b64.c, then rewritten, the bugs are all mine */
104 frombase64(char *dst
, const char *src
, size_t size
, int flag
)
115 for (dstc
= 0, srcc
= 0 ; srcc
< size
; ) {
116 for (gotc
= 0, i
= 0; i
< 4 && srcc
< size
; i
++) {
117 for (b
= 0x0; srcc
< size
&& b
== 0x0 ; ) {
118 b
= base64s
[(unsigned)src
[srcc
++]];
123 in
[i
] = (uint8_t)(b
- 1);
130 out
[0] = (uint8_t)((unsigned)in
[0] << 2 |
131 (unsigned)in
[1] >> 4);
132 out
[1] = (uint8_t)((unsigned)in
[1] << 4 |
133 (unsigned)in
[2] >> 2);
134 out
[2] = (uint8_t)(((in
[2] << 6) & 0xc0) | in
[3]);
135 for (i
= 0; i
< gotc
- 1; i
++) {
146 /* show hexadecimal/ascii dump */
148 show(const char *header
, char *in
, int len
)
150 char line
[LINELEN
+ 1];
153 printf("%s%s", (header
) ? header
: "", (header
) ? "\n" : "");
154 printf("[%d chars]\n", len
);
155 for (i
= 0 ; i
< len
; i
++) {
156 if (i
% LINELEN
== 0) {
157 printf("%.5d | ", i
);
159 printf("%.02x ", (uint8_t)in
[i
]);
160 line
[i
% LINELEN
] = (isprint(in
[i
])) ? in
[i
] : '.';
161 if (i
% LINELEN
== LINELEN
- 1) {
163 printf(" | %s\n", line
);
166 for ( ; i
% LINELEN
!= 0 ; i
++) {
168 line
[i
% LINELEN
] = ' ';
171 printf(" | %s\n", line
);
174 /* get a bignum from the buffer gap */
176 getbignum(bufgap_t
*bg
, char *buf
, const char *header
)
181 (void) bufgap_getbin(bg
, &len
, sizeof(len
));
183 (void) bufgap_seek(bg
, sizeof(len
), BGFromHere
, BGByte
);
184 (void) bufgap_getbin(bg
, buf
, len
);
185 bignum
= BN_bin2bn((const unsigned char *)buf
, (int)len
, NULL
);
186 if (__ops_get_debug_level(__FILE__
)) {
187 show(header
, buf
, (int)len
);
189 (void) bufgap_seek(bg
, len
, BGFromHere
, BGByte
);
193 static str_t pkatypes
[] = {
194 { "ssh-rsa", 7, OPS_PKA_RSA
},
195 { "ssh-dsa", 7, OPS_PKA_DSA
},
199 /* look for a string in the given array */
201 findstr(str_t
*array
, const char *name
)
205 for (sp
= array
; sp
->s
; sp
++) {
206 if (strncmp(name
, sp
->s
, sp
->len
) == 0) {
213 /* convert an ssh (host) pubkey to a pgp pubkey */
215 __ops_ssh2pubkey(__ops_io_t
*io
, const char *f
, __ops_key_t
*key
)
217 __ops_userid_t userid
;
218 __ops_pubkey_t
*pubkey
;
231 (void) memset(&bg
, 0x0, sizeof(bg
));
232 if (!bufgap_open(&bg
, f
)) {
233 (void) fprintf(stderr
, "can't open '%s'\n", f
);
237 if ((buf
= calloc(1, (size_t)st
.st_size
)) == NULL
) {
238 (void) fprintf(stderr
, "can't calloc %zu bytes for '%s'\n", (size_t)st
.st_size
, f
);
242 if ((bin
= calloc(1, (size_t)st
.st_size
)) == NULL
) {
243 (void) fprintf(stderr
, "can't calloc %zu bytes for '%s'\n", (size_t)st
.st_size
, f
);
249 /* move past ascii type of key */
250 while (bufgap_peek(&bg
, 0) != ' ') {
251 bufgap_seek(&bg
, 1, BGFromHere
, BGByte
);
253 bufgap_seek(&bg
, 1, BGFromHere
, BGByte
);
254 off
= bufgap_tell(&bg
, BGFromBOF
, BGByte
);
256 /* convert from base64 to binary */
257 cc
= bufgap_getbin(&bg
, buf
, (size_t)st
.st_size
);
258 if ((space
= strchr(buf
, ' ')) != NULL
) {
259 cc
= (int)(space
- buf
);
261 if (__ops_get_debug_level(__FILE__
)) {
264 cc
= frombase64(bin
, buf
, (size_t)cc
, 0);
265 if (__ops_get_debug_level(__FILE__
)) {
266 show("decoded base64:", bin
, cc
);
268 bufgap_delete(&bg
, (uint64_t)bufgap_tell(&bg
, BGFromEOF
, BGByte
));
269 bufgap_insert(&bg
, bin
, cc
);
270 bufgap_seek(&bg
, off
, BGFromBOF
, BGByte
);
272 /* get the type of key */
273 (void) bufgap_getbin(&bg
, &len
, sizeof(len
));
275 (void) bufgap_seek(&bg
, sizeof(len
), BGFromHere
, BGByte
);
276 (void) bufgap_getbin(&bg
, buf
, len
);
277 (void) bufgap_seek(&bg
, len
, BGFromHere
, BGByte
);
279 (void) memset(key
, 0x0, sizeof(*key
));
280 pubkey
= &key
->key
.seckey
.pubkey
;
281 pubkey
->version
= OPS_V4
;
282 pubkey
->birthtime
= st
.st_mtime
;
285 switch (pubkey
->alg
= findstr(pkatypes
, buf
)) {
287 /* get the 'e' param of the key */
288 pubkey
->key
.rsa
.e
= getbignum(&bg
, buf
, "RSA E");
289 /* get the 'n' param of the key */
290 pubkey
->key
.rsa
.n
= getbignum(&bg
, buf
, "RSA N");
293 /* get the 'p' param of the key */
294 pubkey
->key
.dsa
.p
= getbignum(&bg
, buf
, "DSA P");
295 /* get the 'q' param of the key */
296 pubkey
->key
.dsa
.q
= getbignum(&bg
, buf
, "DSA Q");
297 /* get the 'g' param of the key */
298 pubkey
->key
.dsa
.g
= getbignum(&bg
, buf
, "DSA G");
299 /* get the 'y' param of the key */
300 pubkey
->key
.dsa
.y
= getbignum(&bg
, buf
, "DSA Y");
303 (void) fprintf(stderr
, "Unrecognised pubkey type %d for '%s'\n",
309 /* check for stragglers */
310 if (ok
&& bufgap_tell(&bg
, BGFromEOF
, BGByte
) > 0) {
311 printf("%"PRIi64
" bytes left\n", bufgap_tell(&bg
, BGFromEOF
, BGByte
));
312 printf("[%s]\n", bufgap_getstr(&bg
));
316 (void) memset(&userid
, 0x0, sizeof(userid
));
317 (void) gethostname(hostname
, sizeof(hostname
));
318 if (strlen(space
+ 1) - 1 == 0) {
319 (void) snprintf(owner
, sizeof(owner
), "<root@%s>",
322 (void) snprintf(owner
, sizeof(owner
), "<%.*s>",
323 (int)strlen(space
+ 1) - 1,
326 (void) __ops_asprintf((char **)(void *)&userid
.userid
,
331 __ops_keyid(key
->key_id
, sizeof(key
->key_id
), pubkey
);
332 __ops_add_userid(key
, &userid
);
333 __ops_fingerprint(&key
->fingerprint
, pubkey
);
335 if (__ops_get_debug_level(__FILE__
)) {
336 __ops_print_keydata(io
, key
, "pub", pubkey
);
345 /* convert an ssh (host) seckey to a pgp seckey */
347 __ops_ssh2seckey(__ops_io_t
*io
, const char *f
, __ops_key_t
*key
, __ops_pubkey_t
*pubkey
)
349 unsigned char sesskey
[CAST_KEY_LENGTH
];
350 unsigned char hashed
[OPS_SHA1_HASH_SIZE
];
351 __ops_crypt_t crypted
;
353 unsigned int done
= 0;
356 /* XXX - check for rsa/dsa */
357 if (!openssl_read_pem_seckey(f
, key
, "ssh-rsa")) {
360 if (__ops_get_debug_level(__FILE__
)) {
361 __ops_print_keydata(io
, key
, "sec", &key
->key
.seckey
.pubkey
);
363 /* let's add some sane defaults */
364 (void) memcpy(&key
->key
.seckey
.pubkey
, pubkey
, sizeof(*pubkey
));
365 key
->key
.seckey
.s2k_usage
= OPS_S2KU_ENCRYPTED_AND_HASHED
;
366 key
->key
.seckey
.alg
= OPS_SA_CAST5
;
367 key
->key
.seckey
.s2k_specifier
= OPS_S2KS_SALTED
;
368 key
->key
.seckey
.hash_alg
= OPS_HASH_SHA1
;
369 for (done
= 0, i
= 0; done
< CAST_KEY_LENGTH
; i
++) {
370 unsigned char zero
= 0;
375 needed
= CAST_KEY_LENGTH
- done
;
376 size
= MIN(needed
, OPS_SHA1_HASH_SIZE
);
378 __ops_hash_any(&hash
, key
->key
.seckey
.hash_alg
);
379 if (!hash
.init(&hash
)) {
380 (void) fprintf(stderr
, "write_seckey_body: bad alloc\n");
384 /* preload if iterating */
385 for (j
= 0; j
< i
; j
++) {
387 * Coverity shows a DEADCODE error on this
388 * line. This is expected since the hardcoded
389 * use of SHA1 and CAST5 means that it will
390 * not used. This will change however when
391 * other algorithms are supported.
393 hash
.add(&hash
, &zero
, 1);
396 if (key
->key
.seckey
.s2k_specifier
== OPS_S2KS_SALTED
) {
397 hash
.add(&hash
, key
->key
.seckey
.salt
, OPS_SALT_SIZE
);
399 hash
.finish(&hash
, hashed
);
402 * if more in hash than is needed by session key, use
403 * the leftmost octets
405 (void) memcpy(&sesskey
[i
* OPS_SHA1_HASH_SIZE
],
406 hashed
, (unsigned)size
);
407 done
+= (unsigned)size
;
408 if (done
> CAST_KEY_LENGTH
) {
409 (void) fprintf(stderr
,
410 "write_seckey_body: short add\n");
414 __ops_crypt_any(&crypted
, key
->key
.seckey
.alg
);
415 crypted
.set_iv(&crypted
, key
->key
.seckey
.iv
);
416 crypted
.set_crypt_key(&crypted
, sesskey
);
417 __ops_encrypt_init(&crypted
);
418 key
->key
.seckey
.pubkey
.alg
= OPS_PKA_RSA
;
419 __ops_fingerprint(&key
->fingerprint
, pubkey
);
420 __ops_keyid(key
->key_id
, sizeof(key
->key_id
), pubkey
);
424 /* read a key from the ssh file, and add it to a keyring */
426 __ops_ssh2_readkeys(__ops_io_t
*io
, __ops_keyring_t
*pubring
,
427 __ops_keyring_t
*secring
, const char *pubfile
,
435 (void) memset(&key
, 0x0, sizeof(key
));
437 if (__ops_get_debug_level(__FILE__
)) {
438 (void) fprintf(io
->errs
, "__ops_ssh2_readkeys: pubfile '%s'\n", pubfile
);
440 __ops_ssh2pubkey(io
, pubfile
, &key
);
441 EXPAND_ARRAY(pubring
, key
);
442 pubkey
= &pubring
->keys
[pubring
->keyc
++];
443 (void) memcpy(pubkey
, &key
, sizeof(key
));
444 pubkey
->type
= OPS_PTAG_CT_PUBLIC_KEY
;
447 if (__ops_get_debug_level(__FILE__
)) {
448 (void) fprintf(io
->errs
, "__ops_ssh2_readkeys: secfile '%s'\n", secfile
);
450 if (pubkey
== NULL
) {
451 pubkey
= &pubring
->keys
[0];
453 (void) __ops_ssh2seckey(io
, secfile
, &key
, &pubkey
->key
.pubkey
);
454 EXPAND_ARRAY(secring
, key
);
455 seckey
= &secring
->keys
[secring
->keyc
++];
456 (void) memcpy(seckey
, &key
, sizeof(key
));
457 seckey
->type
= OPS_PTAG_CT_SECRET_KEY
;