summaryrefslogtreecommitdiff
path: root/src/lib/libssl/ssl_cert.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/lib/libssl/ssl_cert.c680
1 files changed, 0 insertions, 680 deletions
diff --git a/src/lib/libssl/ssl_cert.c b/src/lib/libssl/ssl_cert.c
deleted file mode 100644
index 30e99ad184..0000000000
--- a/src/lib/libssl/ssl_cert.c
+++ /dev/null
@@ -1,680 +0,0 @@
1/* $OpenBSD: ssl_cert.c,v 1.95 2022/02/05 14:54:10 jsing Exp $ */
2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved.
4 *
5 * This package is an SSL implementation written
6 * by Eric Young (eay@cryptsoft.com).
7 * The implementation was written so as to conform with Netscapes SSL.
8 *
9 * This library is free for commercial and non-commercial use as long as
10 * the following conditions are aheared to. The following conditions
11 * apply to all code found in this distribution, be it the RC4, RSA,
12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation
13 * included with this distribution is covered by the same copyright terms
14 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15 *
16 * Copyright remains Eric Young's, and as such any Copyright notices in
17 * the code are not to be removed.
18 * If this package is used in a product, Eric Young should be given attribution
19 * as the author of the parts of the library used.
20 * This can be in the form of a textual message at program startup or
21 * in documentation (online or textual) provided with the package.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 * 1. Redistributions of source code must retain the copyright
27 * notice, this list of conditions and the following disclaimer.
28 * 2. Redistributions in binary form must reproduce the above copyright
29 * notice, this list of conditions and the following disclaimer in the
30 * documentation and/or other materials provided with the distribution.
31 * 3. All advertising materials mentioning features or use of this software
32 * must display the following acknowledgement:
33 * "This product includes cryptographic software written by
34 * Eric Young (eay@cryptsoft.com)"
35 * The word 'cryptographic' can be left out if the rouines from the library
36 * being used are not cryptographic related :-).
37 * 4. If you include any Windows specific code (or a derivative thereof) from
38 * the apps directory (application code) you must include an acknowledgement:
39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40 *
41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51 * SUCH DAMAGE.
52 *
53 * The licence and distribution terms for any publically available version or
54 * derivative of this code cannot be changed. i.e. this code cannot simply be
55 * copied and put under another distribution licence
56 * [including the GNU Public Licence.]
57 */
58/* ====================================================================
59 * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved.
60 *
61 * Redistribution and use in source and binary forms, with or without
62 * modification, are permitted provided that the following conditions
63 * are met:
64 *
65 * 1. Redistributions of source code must retain the above copyright
66 * notice, this list of conditions and the following disclaimer.
67 *
68 * 2. Redistributions in binary form must reproduce the above copyright
69 * notice, this list of conditions and the following disclaimer in
70 * the documentation and/or other materials provided with the
71 * distribution.
72 *
73 * 3. All advertising materials mentioning features or use of this
74 * software must display the following acknowledgment:
75 * "This product includes software developed by the OpenSSL Project
76 * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
77 *
78 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
79 * endorse or promote products derived from this software without
80 * prior written permission. For written permission, please contact
81 * openssl-core@openssl.org.
82 *
83 * 5. Products derived from this software may not be called "OpenSSL"
84 * nor may "OpenSSL" appear in their names without prior written
85 * permission of the OpenSSL Project.
86 *
87 * 6. Redistributions of any form whatsoever must retain the following
88 * acknowledgment:
89 * "This product includes software developed by the OpenSSL Project
90 * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
91 *
92 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
93 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
94 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
95 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
96 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
97 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
98 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
99 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
100 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
101 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
102 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
103 * OF THE POSSIBILITY OF SUCH DAMAGE.
104 * ====================================================================
105 *
106 * This product includes cryptographic software written by Eric Young
107 * (eay@cryptsoft.com). This product includes software written by Tim
108 * Hudson (tjh@cryptsoft.com).
109 *
110 */
111/* ====================================================================
112 * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
113 * ECC cipher suite support in OpenSSL originally developed by
114 * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
115 */
116
117#include <sys/types.h>
118
119#include <dirent.h>
120#include <stdio.h>
121#include <unistd.h>
122
123#include <openssl/bio.h>
124#include <openssl/bn.h>
125#include <openssl/dh.h>
126#include <openssl/objects.h>
127#include <openssl/opensslconf.h>
128#include <openssl/pem.h>
129#include <openssl/x509v3.h>
130
131#include "ssl_locl.h"
132
133int
134SSL_get_ex_data_X509_STORE_CTX_idx(void)
135{
136 static volatile int ssl_x509_store_ctx_idx = -1;
137 int got_write_lock = 0;
138
139 CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
140
141 if (ssl_x509_store_ctx_idx < 0) {
142 CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
143 CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
144 got_write_lock = 1;
145
146 if (ssl_x509_store_ctx_idx < 0) {
147 ssl_x509_store_ctx_idx =
148 X509_STORE_CTX_get_ex_new_index(
149 0, "SSL for verify callback", NULL, NULL, NULL);
150 }
151 }
152
153 if (got_write_lock)
154 CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
155 else
156 CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
157
158 return ssl_x509_store_ctx_idx;
159}
160
161SSL_CERT *
162ssl_cert_new(void)
163{
164 SSL_CERT *ret;
165
166 ret = calloc(1, sizeof(SSL_CERT));
167 if (ret == NULL) {
168 SSLerrorx(ERR_R_MALLOC_FAILURE);
169 return (NULL);
170 }
171 ret->key = &(ret->pkeys[SSL_PKEY_RSA]);
172 ret->references = 1;
173 return (ret);
174}
175
176SSL_CERT *
177ssl_cert_dup(SSL_CERT *cert)
178{
179 SSL_CERT *ret;
180 int i;
181
182 ret = calloc(1, sizeof(SSL_CERT));
183 if (ret == NULL) {
184 SSLerrorx(ERR_R_MALLOC_FAILURE);
185 return (NULL);
186 }
187
188 /*
189 * same as ret->key = ret->pkeys + (cert->key - cert->pkeys),
190 * if you find that more readable
191 */
192 ret->key = &ret->pkeys[cert->key - &cert->pkeys[0]];
193
194 ret->valid = cert->valid;
195 ret->mask_k = cert->mask_k;
196 ret->mask_a = cert->mask_a;
197
198 if (cert->dhe_params != NULL) {
199 ret->dhe_params = DHparams_dup(cert->dhe_params);
200 if (ret->dhe_params == NULL) {
201 SSLerrorx(ERR_R_DH_LIB);
202 goto err;
203 }
204 }
205 ret->dhe_params_cb = cert->dhe_params_cb;
206 ret->dhe_params_auto = cert->dhe_params_auto;
207
208 for (i = 0; i < SSL_PKEY_NUM; i++) {
209 if (cert->pkeys[i].x509 != NULL) {
210 ret->pkeys[i].x509 = cert->pkeys[i].x509;
211 X509_up_ref(ret->pkeys[i].x509);
212 }
213
214 if (cert->pkeys[i].privatekey != NULL) {
215 ret->pkeys[i].privatekey = cert->pkeys[i].privatekey;
216 EVP_PKEY_up_ref(ret->pkeys[i].privatekey);
217 switch (i) {
218 /*
219 * If there was anything special to do for
220 * certain types of keys, we'd do it here.
221 * (Nothing at the moment, I think.)
222 */
223
224 case SSL_PKEY_RSA:
225 /* We have an RSA key. */
226 break;
227
228 case SSL_PKEY_ECC:
229 /* We have an ECC key */
230 break;
231
232 case SSL_PKEY_GOST01:
233 /* We have a GOST key */
234 break;
235
236 default:
237 /* Can't happen. */
238 SSLerrorx(SSL_R_LIBRARY_BUG);
239 }
240 }
241
242 if (cert->pkeys[i].chain != NULL) {
243 if ((ret->pkeys[i].chain =
244 X509_chain_up_ref(cert->pkeys[i].chain)) == NULL)
245 goto err;
246 }
247 }
248
249 /*
250 * ret->extra_certs *should* exist, but currently the own certificate
251 * chain is held inside SSL_CTX
252 */
253
254 ret->references = 1;
255
256 return (ret);
257
258 err:
259 DH_free(ret->dhe_params);
260
261 for (i = 0; i < SSL_PKEY_NUM; i++) {
262 X509_free(ret->pkeys[i].x509);
263 EVP_PKEY_free(ret->pkeys[i].privatekey);
264 sk_X509_pop_free(ret->pkeys[i].chain, X509_free);
265 }
266 free (ret);
267 return NULL;
268}
269
270
271void
272ssl_cert_free(SSL_CERT *c)
273{
274 int i;
275
276 if (c == NULL)
277 return;
278
279 i = CRYPTO_add(&c->references, -1, CRYPTO_LOCK_SSL_CERT);
280 if (i > 0)
281 return;
282
283 DH_free(c->dhe_params);
284
285 for (i = 0; i < SSL_PKEY_NUM; i++) {
286 X509_free(c->pkeys[i].x509);
287 EVP_PKEY_free(c->pkeys[i].privatekey);
288 sk_X509_pop_free(c->pkeys[i].chain, X509_free);
289 }
290
291 free(c);
292}
293
294int
295ssl_cert_set0_chain(SSL_CERT *c, STACK_OF(X509) *chain)
296{
297 if (c->key == NULL)
298 return 0;
299
300 sk_X509_pop_free(c->key->chain, X509_free);
301 c->key->chain = chain;
302
303 return 1;
304}
305
306int
307ssl_cert_set1_chain(SSL_CERT *c, STACK_OF(X509) *chain)
308{
309 STACK_OF(X509) *new_chain = NULL;
310
311 if (chain != NULL) {
312 if ((new_chain = X509_chain_up_ref(chain)) == NULL)
313 return 0;
314 }
315 if (!ssl_cert_set0_chain(c, new_chain)) {
316 sk_X509_pop_free(new_chain, X509_free);
317 return 0;
318 }
319
320 return 1;
321}
322
323int
324ssl_cert_add0_chain_cert(SSL_CERT *c, X509 *cert)
325{
326 if (c->key == NULL)
327 return 0;
328
329 if (c->key->chain == NULL) {
330 if ((c->key->chain = sk_X509_new_null()) == NULL)
331 return 0;
332 }
333 if (!sk_X509_push(c->key->chain, cert))
334 return 0;
335
336 return 1;
337}
338
339int
340ssl_cert_add1_chain_cert(SSL_CERT *c, X509 *cert)
341{
342 if (!ssl_cert_add0_chain_cert(c, cert))
343 return 0;
344
345 X509_up_ref(cert);
346
347 return 1;
348}
349
350int
351ssl_verify_cert_chain(SSL *s, STACK_OF(X509) *sk)
352{
353 X509_STORE_CTX *ctx = NULL;
354 X509 *x;
355 int ret = 0;
356
357 if ((sk == NULL) || (sk_X509_num(sk) == 0))
358 goto err;
359
360 if ((ctx = X509_STORE_CTX_new()) == NULL)
361 goto err;
362
363 x = sk_X509_value(sk, 0);
364 if (!X509_STORE_CTX_init(ctx, s->ctx->cert_store, x, sk)) {
365 SSLerror(s, ERR_R_X509_LIB);
366 goto err;
367 }
368 X509_STORE_CTX_set_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx(), s);
369
370 /*
371 * We need to inherit the verify parameters. These can be
372 * determined by the context: if its a server it will verify
373 * SSL client certificates or vice versa.
374 */
375 X509_STORE_CTX_set_default(ctx, s->server ? "ssl_client" : "ssl_server");
376
377 /*
378 * Anything non-default in "param" should overwrite anything
379 * in the ctx.
380 */
381 X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(ctx), s->param);
382
383 if (s->internal->verify_callback)
384 X509_STORE_CTX_set_verify_cb(ctx, s->internal->verify_callback);
385
386 if (s->ctx->internal->app_verify_callback != NULL)
387 ret = s->ctx->internal->app_verify_callback(ctx,
388 s->ctx->internal->app_verify_arg);
389 else
390 ret = X509_verify_cert(ctx);
391
392 s->verify_result = X509_STORE_CTX_get_error(ctx);
393 sk_X509_pop_free(s->internal->verified_chain, X509_free);
394 s->internal->verified_chain = NULL;
395 if (X509_STORE_CTX_get0_chain(ctx) != NULL) {
396 s->internal->verified_chain = X509_STORE_CTX_get1_chain(ctx);
397 if (s->internal->verified_chain == NULL) {
398 SSLerrorx(ERR_R_MALLOC_FAILURE);
399 ret = 0;
400 }
401 }
402
403 err:
404 X509_STORE_CTX_free(ctx);
405
406 return (ret);
407}
408
409static void
410set_client_CA_list(STACK_OF(X509_NAME) **ca_list,
411 STACK_OF(X509_NAME) *name_list)
412{
413 sk_X509_NAME_pop_free(*ca_list, X509_NAME_free);
414 *ca_list = name_list;
415}
416
417STACK_OF(X509_NAME) *
418SSL_dup_CA_list(const STACK_OF(X509_NAME) *sk)
419{
420 int i;
421 STACK_OF(X509_NAME) *ret;
422 X509_NAME *name = NULL;
423
424 if ((ret = sk_X509_NAME_new_null()) == NULL)
425 goto err;
426
427 for (i = 0; i < sk_X509_NAME_num(sk); i++) {
428 if ((name = X509_NAME_dup(sk_X509_NAME_value(sk, i))) == NULL)
429 goto err;
430 if (!sk_X509_NAME_push(ret, name))
431 goto err;
432 }
433 return (ret);
434
435 err:
436 X509_NAME_free(name);
437 sk_X509_NAME_pop_free(ret, X509_NAME_free);
438 return NULL;
439}
440
441void
442SSL_set_client_CA_list(SSL *s, STACK_OF(X509_NAME) *name_list)
443{
444 set_client_CA_list(&(s->internal->client_CA), name_list);
445}
446
447void
448SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list)
449{
450 set_client_CA_list(&(ctx->internal->client_CA), name_list);
451}
452
453STACK_OF(X509_NAME) *
454SSL_CTX_get_client_CA_list(const SSL_CTX *ctx)
455{
456 return (ctx->internal->client_CA);
457}
458
459STACK_OF(X509_NAME) *
460SSL_get_client_CA_list(const SSL *s)
461{
462 if (!s->server) {
463 /* We are in the client. */
464 if ((s->version >> 8) == SSL3_VERSION_MAJOR)
465 return (s->s3->hs.tls12.ca_names);
466 else
467 return (NULL);
468 } else {
469 if (s->internal->client_CA != NULL)
470 return (s->internal->client_CA);
471 else
472 return (s->ctx->internal->client_CA);
473 }
474}
475
476static int
477add_client_CA(STACK_OF(X509_NAME) **sk, X509 *x)
478{
479 X509_NAME *name;
480
481 if (x == NULL)
482 return (0);
483 if ((*sk == NULL) && ((*sk = sk_X509_NAME_new_null()) == NULL))
484 return (0);
485
486 if ((name = X509_NAME_dup(X509_get_subject_name(x))) == NULL)
487 return (0);
488
489 if (!sk_X509_NAME_push(*sk, name)) {
490 X509_NAME_free(name);
491 return (0);
492 }
493 return (1);
494}
495
496int
497SSL_add_client_CA(SSL *ssl, X509 *x)
498{
499 return (add_client_CA(&(ssl->internal->client_CA), x));
500}
501
502int
503SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x)
504{
505 return (add_client_CA(&(ctx->internal->client_CA), x));
506}
507
508static int
509xname_cmp(const X509_NAME * const *a, const X509_NAME * const *b)
510{
511 return (X509_NAME_cmp(*a, *b));
512}
513
514/*!
515 * Load CA certs from a file into a ::STACK. Note that it is somewhat misnamed;
516 * it doesn't really have anything to do with clients (except that a common use
517 * for a stack of CAs is to send it to the client). Actually, it doesn't have
518 * much to do with CAs, either, since it will load any old cert.
519 * \param file the file containing one or more certs.
520 * \return a ::STACK containing the certs.
521 */
522STACK_OF(X509_NAME) *
523SSL_load_client_CA_file(const char *file)
524{
525 BIO *in;
526 X509 *x = NULL;
527 X509_NAME *xn = NULL;
528 STACK_OF(X509_NAME) *ret = NULL, *sk;
529
530 sk = sk_X509_NAME_new(xname_cmp);
531
532 in = BIO_new(BIO_s_file());
533
534 if ((sk == NULL) || (in == NULL)) {
535 SSLerrorx(ERR_R_MALLOC_FAILURE);
536 goto err;
537 }
538
539 if (!BIO_read_filename(in, file))
540 goto err;
541
542 for (;;) {
543 if (PEM_read_bio_X509(in, &x, NULL, NULL) == NULL)
544 break;
545 if (ret == NULL) {
546 ret = sk_X509_NAME_new_null();
547 if (ret == NULL) {
548 SSLerrorx(ERR_R_MALLOC_FAILURE);
549 goto err;
550 }
551 }
552 if ((xn = X509_get_subject_name(x)) == NULL)
553 goto err;
554 /* check for duplicates */
555 xn = X509_NAME_dup(xn);
556 if (xn == NULL)
557 goto err;
558 if (sk_X509_NAME_find(sk, xn) >= 0)
559 X509_NAME_free(xn);
560 else {
561 if (!sk_X509_NAME_push(sk, xn))
562 goto err;
563 if (!sk_X509_NAME_push(ret, xn))
564 goto err;
565 }
566 }
567
568 if (0) {
569 err:
570 sk_X509_NAME_pop_free(ret, X509_NAME_free);
571 ret = NULL;
572 }
573 sk_X509_NAME_free(sk);
574 BIO_free(in);
575 X509_free(x);
576 if (ret != NULL)
577 ERR_clear_error();
578
579 return (ret);
580}
581
582/*!
583 * Add a file of certs to a stack.
584 * \param stack the stack to add to.
585 * \param file the file to add from. All certs in this file that are not
586 * already in the stack will be added.
587 * \return 1 for success, 0 for failure. Note that in the case of failure some
588 * certs may have been added to \c stack.
589 */
590
591int
592SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
593 const char *file)
594{
595 BIO *in;
596 X509 *x = NULL;
597 X509_NAME *xn = NULL;
598 int ret = 1;
599 int (*oldcmp)(const X509_NAME * const *a, const X509_NAME * const *b);
600
601 oldcmp = sk_X509_NAME_set_cmp_func(stack, xname_cmp);
602
603 in = BIO_new(BIO_s_file());
604
605 if (in == NULL) {
606 SSLerrorx(ERR_R_MALLOC_FAILURE);
607 goto err;
608 }
609
610 if (!BIO_read_filename(in, file))
611 goto err;
612
613 for (;;) {
614 if (PEM_read_bio_X509(in, &x, NULL, NULL) == NULL)
615 break;
616 if ((xn = X509_get_subject_name(x)) == NULL)
617 goto err;
618 xn = X509_NAME_dup(xn);
619 if (xn == NULL)
620 goto err;
621 if (sk_X509_NAME_find(stack, xn) >= 0)
622 X509_NAME_free(xn);
623 else
624 if (!sk_X509_NAME_push(stack, xn))
625 goto err;
626 }
627
628 ERR_clear_error();
629
630 if (0) {
631 err:
632 ret = 0;
633 }
634 BIO_free(in);
635 X509_free(x);
636
637 (void)sk_X509_NAME_set_cmp_func(stack, oldcmp);
638
639 return ret;
640}
641
642/*!
643 * Add a directory of certs to a stack.
644 * \param stack the stack to append to.
645 * \param dir the directory to append from. All files in this directory will be
646 * examined as potential certs. Any that are acceptable to
647 * SSL_add_dir_cert_subjects_to_stack() that are not already in the stack will
648 * be included.
649 * \return 1 for success, 0 for failure. Note that in the case of failure some
650 * certs may have been added to \c stack.
651 */
652
653int
654SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, const char *dir)
655{
656 DIR *dirp = NULL;
657 char *path = NULL;
658 int ret = 0;
659
660 dirp = opendir(dir);
661 if (dirp) {
662 struct dirent *dp;
663 while ((dp = readdir(dirp)) != NULL) {
664 if (asprintf(&path, "%s/%s", dir, dp->d_name) != -1) {
665 ret = SSL_add_file_cert_subjects_to_stack(
666 stack, path);
667 free(path);
668 }
669 if (!ret)
670 break;
671 }
672 (void) closedir(dirp);
673 }
674 if (!ret) {
675 SYSerror(errno);
676 ERR_asprintf_error_data("opendir ('%s')", dir);
677 SSLerrorx(ERR_R_SYS_LIB);
678 }
679 return ret;
680}