Annotation of src/usr.bin/ssh/key.c, Revision 1.12
1.1 markus 1: /*
1.11 deraadt 2: * read_bignum():
3: * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4: *
5: * As far as I am concerned, the code I have written for this software
6: * can be used freely for any purpose. Any derived versions of this
7: * software must be clearly marked as such, and if the derived work is
8: * incompatible with the protocol description in the RFC file, it must be
9: * called by a name other than "ssh" or "Secure Shell".
10: *
11: *
1.1 markus 12: * Copyright (c) 2000 Markus Friedl. All rights reserved.
13: *
14: * Redistribution and use in source and binary forms, with or without
15: * modification, are permitted provided that the following conditions
16: * are met:
17: * 1. Redistributions of source code must retain the above copyright
18: * notice, this list of conditions and the following disclaimer.
19: * 2. Redistributions in binary form must reproduce the above copyright
20: * notice, this list of conditions and the following disclaimer in the
21: * documentation and/or other materials provided with the distribution.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33: */
34:
35: #include "includes.h"
36: #include "ssh.h"
1.2 markus 37: #include <openssl/rsa.h>
38: #include <openssl/dsa.h>
39: #include <openssl/evp.h>
1.1 markus 40: #include "xmalloc.h"
41: #include "key.h"
1.12 ! markus 42: #include "rsa.h"
! 43: #include "ssh-dss.h"
! 44: #include "ssh-rsa.h"
1.3 markus 45: #include "uuencode.h"
1.12 ! markus 46: #include "buffer.h"
! 47: #include "bufaux.h"
1.3 markus 48:
1.12 ! markus 49: RCSID("$OpenBSD: key.c,v 1.11 2000/09/07 20:27:51 deraadt Exp $");
1.1 markus 50:
51: Key *
52: key_new(int type)
53: {
54: Key *k;
55: RSA *rsa;
56: DSA *dsa;
57: k = xmalloc(sizeof(*k));
58: k->type = type;
1.3 markus 59: k->dsa = NULL;
60: k->rsa = NULL;
1.1 markus 61: switch (k->type) {
1.12 ! markus 62: case KEY_RSA1:
1.1 markus 63: case KEY_RSA:
64: rsa = RSA_new();
65: rsa->n = BN_new();
66: rsa->e = BN_new();
67: k->rsa = rsa;
68: break;
69: case KEY_DSA:
70: dsa = DSA_new();
71: dsa->p = BN_new();
72: dsa->q = BN_new();
73: dsa->g = BN_new();
74: dsa->pub_key = BN_new();
75: k->dsa = dsa;
76: break;
1.12 ! markus 77: case KEY_UNSPEC:
1.1 markus 78: break;
79: default:
80: fatal("key_new: bad key type %d", k->type);
81: break;
82: }
83: return k;
84: }
1.12 ! markus 85: Key *
! 86: key_new_private(int type)
! 87: {
! 88: Key *k = key_new(type);
! 89: switch (k->type) {
! 90: case KEY_RSA1:
! 91: case KEY_RSA:
! 92: k->rsa->d = BN_new();
! 93: k->rsa->iqmp = BN_new();
! 94: k->rsa->q = BN_new();
! 95: k->rsa->p = BN_new();
! 96: k->rsa->dmq1 = BN_new();
! 97: k->rsa->dmp1 = BN_new();
! 98: break;
! 99: case KEY_DSA:
! 100: k->dsa->priv_key = BN_new();
! 101: break;
! 102: case KEY_UNSPEC:
! 103: break;
! 104: default:
! 105: break;
! 106: }
! 107: return k;
! 108: }
1.1 markus 109: void
110: key_free(Key *k)
111: {
112: switch (k->type) {
1.12 ! markus 113: case KEY_RSA1:
1.1 markus 114: case KEY_RSA:
115: if (k->rsa != NULL)
116: RSA_free(k->rsa);
117: k->rsa = NULL;
118: break;
119: case KEY_DSA:
120: if (k->dsa != NULL)
121: DSA_free(k->dsa);
122: k->dsa = NULL;
123: break;
1.12 ! markus 124: case KEY_UNSPEC:
! 125: break;
1.1 markus 126: default:
127: fatal("key_free: bad key type %d", k->type);
128: break;
129: }
130: xfree(k);
131: }
132: int
133: key_equal(Key *a, Key *b)
134: {
135: if (a == NULL || b == NULL || a->type != b->type)
136: return 0;
137: switch (a->type) {
1.12 ! markus 138: case KEY_RSA1:
1.1 markus 139: case KEY_RSA:
140: return a->rsa != NULL && b->rsa != NULL &&
141: BN_cmp(a->rsa->e, b->rsa->e) == 0 &&
142: BN_cmp(a->rsa->n, b->rsa->n) == 0;
143: break;
144: case KEY_DSA:
145: return a->dsa != NULL && b->dsa != NULL &&
146: BN_cmp(a->dsa->p, b->dsa->p) == 0 &&
147: BN_cmp(a->dsa->q, b->dsa->q) == 0 &&
148: BN_cmp(a->dsa->g, b->dsa->g) == 0 &&
149: BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0;
150: break;
151: default:
1.3 markus 152: fatal("key_equal: bad key type %d", a->type);
1.1 markus 153: break;
154: }
155: return 0;
156: }
157:
158: /*
159: * Generate key fingerprint in ascii format.
160: * Based on ideas and code from Bjoern Groenvall <bg@sics.se>
161: */
162: char *
163: key_fingerprint(Key *k)
164: {
1.8 markus 165: static char retval[(EVP_MAX_MD_SIZE+1)*3];
1.3 markus 166: unsigned char *blob = NULL;
1.1 markus 167: int len = 0;
1.3 markus 168: int nlen, elen;
1.1 markus 169:
1.12 ! markus 170: retval[0] = '\0';
1.1 markus 171: switch (k->type) {
1.12 ! markus 172: case KEY_RSA1:
1.1 markus 173: nlen = BN_num_bytes(k->rsa->n);
174: elen = BN_num_bytes(k->rsa->e);
175: len = nlen + elen;
1.3 markus 176: blob = xmalloc(len);
177: BN_bn2bin(k->rsa->n, blob);
178: BN_bn2bin(k->rsa->e, blob + nlen);
1.1 markus 179: break;
180: case KEY_DSA:
1.12 ! markus 181: case KEY_RSA:
! 182: key_to_blob(k, &blob, &len);
! 183: break;
! 184: case KEY_UNSPEC:
! 185: return retval;
1.1 markus 186: break;
187: default:
188: fatal("key_fingerprint: bad key type %d", k->type);
189: break;
190: }
1.3 markus 191: if (blob != NULL) {
1.8 markus 192: int i;
193: unsigned char digest[EVP_MAX_MD_SIZE];
194: EVP_MD *md = EVP_md5();
195: EVP_MD_CTX ctx;
196: EVP_DigestInit(&ctx, md);
197: EVP_DigestUpdate(&ctx, blob, len);
198: EVP_DigestFinal(&ctx, digest, NULL);
199: for(i = 0; i < md->md_size; i++) {
200: char hex[4];
201: snprintf(hex, sizeof(hex), "%02x:", digest[i]);
202: strlcat(retval, hex, sizeof(retval));
203: }
204: retval[strlen(retval) - 1] = '\0';
1.3 markus 205: memset(blob, 0, len);
206: xfree(blob);
1.1 markus 207: }
208: return retval;
209: }
210:
211: /*
212: * Reads a multiple-precision integer in decimal from the buffer, and advances
213: * the pointer. The integer must already be initialized. This function is
214: * permitted to modify the buffer. This leaves *cpp to point just beyond the
215: * last processed (and maybe modified) character. Note that this may modify
216: * the buffer containing the number.
217: */
218: int
219: read_bignum(char **cpp, BIGNUM * value)
220: {
221: char *cp = *cpp;
222: int old;
223:
224: /* Skip any leading whitespace. */
225: for (; *cp == ' ' || *cp == '\t'; cp++)
226: ;
227:
228: /* Check that it begins with a decimal digit. */
229: if (*cp < '0' || *cp > '9')
230: return 0;
231:
232: /* Save starting position. */
233: *cpp = cp;
234:
235: /* Move forward until all decimal digits skipped. */
236: for (; *cp >= '0' && *cp <= '9'; cp++)
237: ;
238:
239: /* Save the old terminating character, and replace it by \0. */
240: old = *cp;
241: *cp = 0;
242:
243: /* Parse the number. */
244: if (BN_dec2bn(&value, *cpp) == 0)
245: return 0;
246:
247: /* Restore old terminating character. */
248: *cp = old;
249:
250: /* Move beyond the number and return success. */
251: *cpp = cp;
252: return 1;
253: }
254: int
255: write_bignum(FILE *f, BIGNUM *num)
256: {
257: char *buf = BN_bn2dec(num);
258: if (buf == NULL) {
259: error("write_bignum: BN_bn2dec() failed");
260: return 0;
261: }
262: fprintf(f, " %s", buf);
263: free(buf);
264: return 1;
265: }
1.12 ! markus 266:
! 267: /* returns 1 ok, -1 error, 0 type mismatch */
! 268: int
1.3 markus 269: key_read(Key *ret, char **cpp)
1.1 markus 270: {
1.3 markus 271: Key *k;
1.12 ! markus 272: int success = -1;
! 273: char *cp, *space;
! 274: int len, n, type;
! 275: u_int bits;
1.3 markus 276: unsigned char *blob;
277:
278: cp = *cpp;
279:
1.1 markus 280: switch(ret->type) {
1.12 ! markus 281: case KEY_RSA1:
1.3 markus 282: /* Get number of bits. */
283: if (*cp < '0' || *cp > '9')
1.12 ! markus 284: return -1; /* Bad bit count... */
1.3 markus 285: for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
286: bits = 10 * bits + *cp - '0';
1.1 markus 287: if (bits == 0)
1.12 ! markus 288: return -1;
1.3 markus 289: *cpp = cp;
1.1 markus 290: /* Get public exponent, public modulus. */
291: if (!read_bignum(cpp, ret->rsa->e))
1.12 ! markus 292: return -1;
1.1 markus 293: if (!read_bignum(cpp, ret->rsa->n))
1.12 ! markus 294: return -1;
! 295: success = 1;
1.1 markus 296: break;
1.12 ! markus 297: case KEY_UNSPEC:
! 298: case KEY_RSA:
1.1 markus 299: case KEY_DSA:
1.12 ! markus 300: space = strchr(cp, ' ');
! 301: if (space == NULL) {
! 302: debug3("key_read: no space");
! 303: return -1;
! 304: }
! 305: *space = '\0';
! 306: type = key_type_from_name(cp);
! 307: *space = ' ';
! 308: if (type == KEY_UNSPEC) {
! 309: debug3("key_read: no key found");
! 310: return -1;
! 311: }
! 312: cp = space+1;
! 313: if (*cp == '\0') {
! 314: debug3("key_read: short string");
! 315: return -1;
! 316: }
! 317: if (ret->type == KEY_UNSPEC) {
! 318: ret->type = type;
! 319: } else if (ret->type != type) {
! 320: /* is a key, but different type */
! 321: debug3("key_read: type mismatch");
1.1 markus 322: return 0;
1.12 ! markus 323: }
1.3 markus 324: len = 2*strlen(cp);
325: blob = xmalloc(len);
326: n = uudecode(cp, blob, len);
1.6 markus 327: if (n < 0) {
1.7 markus 328: error("key_read: uudecode %s failed", cp);
1.12 ! markus 329: return -1;
1.6 markus 330: }
1.12 ! markus 331: k = key_from_blob(blob, n);
1.7 markus 332: if (k == NULL) {
1.12 ! markus 333: error("key_read: key_from_blob %s failed", cp);
! 334: return -1;
1.7 markus 335: }
1.3 markus 336: xfree(blob);
1.12 ! markus 337: if (k->type != type) {
! 338: error("key_read: type mismatch: encoding error");
! 339: key_free(k);
! 340: return -1;
! 341: }
! 342: /*XXXX*/
! 343: if (ret->type == KEY_RSA) {
! 344: if (ret->rsa != NULL)
! 345: RSA_free(ret->rsa);
! 346: ret->rsa = k->rsa;
! 347: k->rsa = NULL;
! 348: success = 1;
! 349: #ifdef DEBUG_PK
! 350: RSA_print_fp(stderr, ret->rsa, 8);
! 351: #endif
! 352: } else {
! 353: if (ret->dsa != NULL)
! 354: DSA_free(ret->dsa);
! 355: ret->dsa = k->dsa;
! 356: k->dsa = NULL;
! 357: success = 1;
! 358: #ifdef DEBUG_PK
! 359: DSA_print_fp(stderr, ret->dsa, 8);
! 360: #endif
! 361: }
! 362: /*XXXX*/
! 363: if (success != 1)
! 364: break;
1.3 markus 365: key_free(k);
1.7 markus 366: /* advance cp: skip whitespace and data */
367: while (*cp == ' ' || *cp == '\t')
368: cp++;
369: while (*cp != '\0' && *cp != ' ' && *cp != '\t')
370: cp++;
371: *cpp = cp;
1.1 markus 372: break;
373: default:
1.3 markus 374: fatal("key_read: bad key type: %d", ret->type);
1.1 markus 375: break;
376: }
1.12 ! markus 377: return success;
1.1 markus 378: }
379: int
380: key_write(Key *key, FILE *f)
381: {
382: int success = 0;
383: unsigned int bits = 0;
384:
1.12 ! markus 385: if (key->type == KEY_RSA1 && key->rsa != NULL) {
1.1 markus 386: /* size of modulus 'n' */
387: bits = BN_num_bits(key->rsa->n);
388: fprintf(f, "%u", bits);
389: if (write_bignum(f, key->rsa->e) &&
390: write_bignum(f, key->rsa->n)) {
391: success = 1;
392: } else {
393: error("key_write: failed for RSA key");
394: }
1.12 ! markus 395: } else if ((key->type == KEY_DSA && key->dsa != NULL) ||
! 396: (key->type == KEY_RSA && key->rsa != NULL)) {
1.3 markus 397: int len, n;
398: unsigned char *blob, *uu;
1.12 ! markus 399: key_to_blob(key, &blob, &len);
1.3 markus 400: uu = xmalloc(2*len);
1.5 markus 401: n = uuencode(blob, len, uu, 2*len);
402: if (n > 0) {
1.12 ! markus 403: fprintf(f, "%s %s", key_ssh_name(key), uu);
1.5 markus 404: success = 1;
405: }
1.3 markus 406: xfree(blob);
407: xfree(uu);
1.1 markus 408: }
409: return success;
410: }
1.4 markus 411: char *
412: key_type(Key *k)
413: {
414: switch (k->type) {
1.12 ! markus 415: case KEY_RSA1:
! 416: return "RSA1";
! 417: break;
1.4 markus 418: case KEY_RSA:
419: return "RSA";
420: break;
421: case KEY_DSA:
422: return "DSA";
423: break;
424: }
425: return "unknown";
1.10 markus 426: }
1.12 ! markus 427: char *
! 428: key_ssh_name(Key *k)
! 429: {
! 430: switch (k->type) {
! 431: case KEY_RSA:
! 432: return "ssh-rsa";
! 433: break;
! 434: case KEY_DSA:
! 435: return "ssh-dss";
! 436: break;
! 437: }
! 438: return "ssh-unknown";
! 439: }
! 440: u_int
1.10 markus 441: key_size(Key *k){
442: switch (k->type) {
1.12 ! markus 443: case KEY_RSA1:
1.10 markus 444: case KEY_RSA:
445: return BN_num_bits(k->rsa->n);
446: break;
447: case KEY_DSA:
448: return BN_num_bits(k->dsa->p);
449: break;
450: }
451: return 0;
1.12 ! markus 452: }
! 453:
! 454: RSA *
! 455: rsa_generate_private_key(unsigned int bits)
! 456: {
! 457: RSA *private;
! 458: private = RSA_generate_key(bits, 35, NULL, NULL);
! 459: if (private == NULL)
! 460: fatal("rsa_generate_private_key: key generation failed.");
! 461: return private;
! 462: }
! 463:
! 464: DSA*
! 465: dsa_generate_private_key(unsigned int bits)
! 466: {
! 467: DSA *private = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, NULL, NULL);
! 468: if (private == NULL)
! 469: fatal("dsa_generate_private_key: DSA_generate_parameters failed");
! 470: if (!DSA_generate_key(private))
! 471: fatal("dsa_generate_private_key: DSA_generate_key failed.");
! 472: if (private == NULL)
! 473: fatal("dsa_generate_private_key: NULL.");
! 474: return private;
! 475: }
! 476:
! 477: Key *
! 478: key_generate(int type, unsigned int bits)
! 479: {
! 480: Key *k = key_new(KEY_UNSPEC);
! 481: switch (type) {
! 482: case KEY_DSA:
! 483: k->dsa = dsa_generate_private_key(bits);
! 484: break;
! 485: case KEY_RSA:
! 486: case KEY_RSA1:
! 487: k->rsa = rsa_generate_private_key(bits);
! 488: break;
! 489: default:
! 490: fatal("key_generate: unknown type %d", type);
! 491: }
! 492: k->type = type;
! 493: return k;
! 494: }
! 495:
! 496: Key *
! 497: key_from_private(Key *k)
! 498: {
! 499: Key *n = NULL;
! 500: switch (k->type) {
! 501: case KEY_DSA:
! 502: n = key_new(k->type);
! 503: BN_copy(n->dsa->p, k->dsa->p);
! 504: BN_copy(n->dsa->q, k->dsa->q);
! 505: BN_copy(n->dsa->g, k->dsa->g);
! 506: BN_copy(n->dsa->pub_key, k->dsa->pub_key);
! 507: break;
! 508: case KEY_RSA:
! 509: case KEY_RSA1:
! 510: n = key_new(k->type);
! 511: BN_copy(n->rsa->n, k->rsa->n);
! 512: BN_copy(n->rsa->e, k->rsa->e);
! 513: break;
! 514: default:
! 515: fatal("key_from_private: unknown type %d", k->type);
! 516: break;
! 517: }
! 518: return n;
! 519: }
! 520:
! 521: int
! 522: key_type_from_name(char *name)
! 523: {
! 524: if (strcmp(name, "rsa1") == 0){
! 525: return KEY_RSA1;
! 526: } else if (strcmp(name, "rsa") == 0){
! 527: return KEY_RSA;
! 528: } else if (strcmp(name, "dsa") == 0){
! 529: return KEY_DSA;
! 530: } else if (strcmp(name, "ssh-rsa") == 0){
! 531: return KEY_RSA;
! 532: } else if (strcmp(name, "ssh-dss") == 0){
! 533: return KEY_DSA;
! 534: }
! 535: debug("key_type_from_name: unknown key type '%s'", name);
! 536: return KEY_UNSPEC;
! 537: }
! 538:
! 539: Key *
! 540: key_from_blob(char *blob, int blen)
! 541: {
! 542: Buffer b;
! 543: char *ktype;
! 544: int rlen, type;
! 545: Key *key = NULL;
! 546:
! 547: #ifdef DEBUG_PK
! 548: dump_base64(stderr, blob, blen);
! 549: #endif
! 550: buffer_init(&b);
! 551: buffer_append(&b, blob, blen);
! 552: ktype = buffer_get_string(&b, NULL);
! 553: type = key_type_from_name(ktype);
! 554:
! 555: switch(type){
! 556: case KEY_RSA:
! 557: key = key_new(type);
! 558: buffer_get_bignum2(&b, key->rsa->n);
! 559: buffer_get_bignum2(&b, key->rsa->e);
! 560: #ifdef DEBUG_PK
! 561: RSA_print_fp(stderr, key->rsa, 8);
! 562: #endif
! 563: break;
! 564: case KEY_DSA:
! 565: key = key_new(type);
! 566: buffer_get_bignum2(&b, key->dsa->p);
! 567: buffer_get_bignum2(&b, key->dsa->q);
! 568: buffer_get_bignum2(&b, key->dsa->g);
! 569: buffer_get_bignum2(&b, key->dsa->pub_key);
! 570: #ifdef DEBUG_PK
! 571: DSA_print_fp(stderr, key->dsa, 8);
! 572: #endif
! 573: break;
! 574: case KEY_UNSPEC:
! 575: key = key_new(type);
! 576: break;
! 577: default:
! 578: error("key_from_blob: cannot handle type %s", ktype);
! 579: break;
! 580: }
! 581: rlen = buffer_len(&b);
! 582: if (key != NULL && rlen != 0)
! 583: error("key_from_blob: remaining bytes in key blob %d", rlen);
! 584: xfree(ktype);
! 585: buffer_free(&b);
! 586: return key;
! 587: }
! 588:
! 589: int
! 590: key_to_blob(Key *key, unsigned char **blobp, unsigned int *lenp)
! 591: {
! 592: Buffer b;
! 593: int len;
! 594: unsigned char *buf;
! 595:
! 596: if (key == NULL) {
! 597: error("key_to_blob: key == NULL");
! 598: return 0;
! 599: }
! 600: buffer_init(&b);
! 601: switch(key->type){
! 602: case KEY_DSA:
! 603: buffer_put_cstring(&b, key_ssh_name(key));
! 604: buffer_put_bignum2(&b, key->dsa->p);
! 605: buffer_put_bignum2(&b, key->dsa->q);
! 606: buffer_put_bignum2(&b, key->dsa->g);
! 607: buffer_put_bignum2(&b, key->dsa->pub_key);
! 608: break;
! 609: case KEY_RSA:
! 610: buffer_put_cstring(&b, key_ssh_name(key));
! 611: buffer_put_bignum2(&b, key->rsa->n);
! 612: buffer_put_bignum2(&b, key->rsa->e);
! 613: break;
! 614: default:
! 615: error("key_to_blob: illegal key type %d", key->type);
! 616: break;
! 617: }
! 618: len = buffer_len(&b);
! 619: buf = xmalloc(len);
! 620: memcpy(buf, buffer_ptr(&b), len);
! 621: memset(buffer_ptr(&b), 0, len);
! 622: buffer_free(&b);
! 623: if (lenp != NULL)
! 624: *lenp = len;
! 625: if (blobp != NULL)
! 626: *blobp = buf;
! 627: return len;
! 628: }
! 629:
! 630: int
! 631: key_sign(
! 632: Key *key,
! 633: unsigned char **sigp, int *lenp,
! 634: unsigned char *data, int datalen)
! 635: {
! 636: switch(key->type){
! 637: case KEY_DSA:
! 638: return ssh_dss_sign(key, sigp, lenp, data, datalen);
! 639: break;
! 640: case KEY_RSA:
! 641: return ssh_rsa_sign(key, sigp, lenp, data, datalen);
! 642: break;
! 643: default:
! 644: error("key_sign: illegal key type %d", key->type);
! 645: return -1;
! 646: break;
! 647: }
! 648: }
! 649:
! 650: int
! 651: key_verify(
! 652: Key *key,
! 653: unsigned char *signature, int signaturelen,
! 654: unsigned char *data, int datalen)
! 655: {
! 656: switch(key->type){
! 657: case KEY_DSA:
! 658: return ssh_dss_verify(key, signature, signaturelen, data, datalen);
! 659: break;
! 660: case KEY_RSA:
! 661: return ssh_rsa_verify(key, signature, signaturelen, data, datalen);
! 662: break;
! 663: default:
! 664: error("key_verify: illegal key type %d", key->type);
! 665: return -1;
! 666: break;
! 667: }
1.4 markus 668: }