1 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
2 | * All rights reserved. |
3 | * |
4 | * This package is an SSL implementation written |
5 | * by Eric Young (eay@cryptsoft.com). |
6 | * The implementation was written so as to conform with Netscapes SSL. |
7 | * |
8 | * This library is free for commercial and non-commercial use as long as |
9 | * the following conditions are aheared to. The following conditions |
10 | * apply to all code found in this distribution, be it the RC4, RSA, |
11 | * lhash, DES, etc., code; not just the SSL code. The SSL documentation |
12 | * included with this distribution is covered by the same copyright terms |
13 | * except that the holder is Tim Hudson (tjh@cryptsoft.com). |
14 | * |
15 | * Copyright remains Eric Young's, and as such any Copyright notices in |
16 | * the code are not to be removed. |
17 | * If this package is used in a product, Eric Young should be given attribution |
18 | * as the author of the parts of the library used. |
19 | * This can be in the form of a textual message at program startup or |
20 | * in documentation (online or textual) provided with the package. |
21 | * |
22 | * Redistribution and use in source and binary forms, with or without |
23 | * modification, are permitted provided that the following conditions |
24 | * are met: |
25 | * 1. Redistributions of source code must retain the copyright |
26 | * notice, this list of conditions and the following disclaimer. |
27 | * 2. Redistributions in binary form must reproduce the above copyright |
28 | * notice, this list of conditions and the following disclaimer in the |
29 | * documentation and/or other materials provided with the distribution. |
30 | * 3. All advertising materials mentioning features or use of this software |
31 | * must display the following acknowledgement: |
32 | * "This product includes cryptographic software written by |
33 | * Eric Young (eay@cryptsoft.com)" |
34 | * The word 'cryptographic' can be left out if the rouines from the library |
35 | * being used are not cryptographic related :-). |
36 | * 4. If you include any Windows specific code (or a derivative thereof) from |
37 | * the apps directory (application code) you must include an acknowledgement: |
38 | * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" |
39 | * |
40 | * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND |
41 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
42 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
43 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
44 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
45 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
46 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
47 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
48 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
49 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
50 | * SUCH DAMAGE. |
51 | * |
52 | * The licence and distribution terms for any publically available version or |
53 | * derivative of this code cannot be changed. i.e. this code cannot simply be |
54 | * copied and put under another distribution licence |
55 | * [including the GNU Public Licence.] */ |
56 | |
57 | #include <openssl/evp.h> |
58 | |
59 | #include <string.h> |
60 | |
61 | #include <openssl/digest.h> |
62 | #include <openssl/err.h> |
63 | #include <openssl/mem.h> |
64 | |
65 | #include "../internal.h" |
66 | #include "internal.h" |
67 | |
68 | |
69 | static const EVP_PKEY_METHOD *const evp_methods[] = { |
70 | &rsa_pkey_meth, |
71 | &ec_pkey_meth, |
72 | &ed25519_pkey_meth, |
73 | }; |
74 | |
75 | static const EVP_PKEY_METHOD *evp_pkey_meth_find(int type) { |
76 | unsigned i; |
77 | |
78 | for (i = 0; i < sizeof(evp_methods)/sizeof(EVP_PKEY_METHOD*); i++) { |
79 | if (evp_methods[i]->pkey_id == type) { |
80 | return evp_methods[i]; |
81 | } |
82 | } |
83 | |
84 | return NULL; |
85 | } |
86 | |
87 | static EVP_PKEY_CTX *evp_pkey_ctx_new(EVP_PKEY *pkey, ENGINE *e, int id) { |
88 | EVP_PKEY_CTX *ret; |
89 | const EVP_PKEY_METHOD *pmeth; |
90 | |
91 | if (id == -1) { |
92 | if (!pkey || !pkey->ameth) { |
93 | return NULL; |
94 | } |
95 | id = pkey->ameth->pkey_id; |
96 | } |
97 | |
98 | pmeth = evp_pkey_meth_find(id); |
99 | |
100 | if (pmeth == NULL) { |
101 | OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); |
102 | ERR_add_error_dataf("algorithm %d" , id); |
103 | return NULL; |
104 | } |
105 | |
106 | ret = OPENSSL_malloc(sizeof(EVP_PKEY_CTX)); |
107 | if (!ret) { |
108 | OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); |
109 | return NULL; |
110 | } |
111 | OPENSSL_memset(ret, 0, sizeof(EVP_PKEY_CTX)); |
112 | |
113 | ret->engine = e; |
114 | ret->pmeth = pmeth; |
115 | ret->operation = EVP_PKEY_OP_UNDEFINED; |
116 | |
117 | if (pkey) { |
118 | EVP_PKEY_up_ref(pkey); |
119 | ret->pkey = pkey; |
120 | } |
121 | |
122 | if (pmeth->init) { |
123 | if (pmeth->init(ret) <= 0) { |
124 | EVP_PKEY_free(ret->pkey); |
125 | OPENSSL_free(ret); |
126 | return NULL; |
127 | } |
128 | } |
129 | |
130 | return ret; |
131 | } |
132 | |
133 | EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e) { |
134 | return evp_pkey_ctx_new(pkey, e, -1); |
135 | } |
136 | |
137 | EVP_PKEY_CTX *EVP_PKEY_CTX_new_id(int id, ENGINE *e) { |
138 | return evp_pkey_ctx_new(NULL, e, id); |
139 | } |
140 | |
141 | void EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx) { |
142 | if (ctx == NULL) { |
143 | return; |
144 | } |
145 | if (ctx->pmeth && ctx->pmeth->cleanup) { |
146 | ctx->pmeth->cleanup(ctx); |
147 | } |
148 | EVP_PKEY_free(ctx->pkey); |
149 | EVP_PKEY_free(ctx->peerkey); |
150 | OPENSSL_free(ctx); |
151 | } |
152 | |
153 | EVP_PKEY_CTX *EVP_PKEY_CTX_dup(EVP_PKEY_CTX *ctx) { |
154 | if (!ctx->pmeth || !ctx->pmeth->copy) { |
155 | return NULL; |
156 | } |
157 | |
158 | EVP_PKEY_CTX *ret = OPENSSL_malloc(sizeof(EVP_PKEY_CTX)); |
159 | if (!ret) { |
160 | return NULL; |
161 | } |
162 | |
163 | OPENSSL_memset(ret, 0, sizeof(EVP_PKEY_CTX)); |
164 | |
165 | ret->pmeth = ctx->pmeth; |
166 | ret->engine = ctx->engine; |
167 | ret->operation = ctx->operation; |
168 | |
169 | if (ctx->pkey != NULL) { |
170 | EVP_PKEY_up_ref(ctx->pkey); |
171 | ret->pkey = ctx->pkey; |
172 | } |
173 | |
174 | if (ctx->peerkey != NULL) { |
175 | EVP_PKEY_up_ref(ctx->peerkey); |
176 | ret->peerkey = ctx->peerkey; |
177 | } |
178 | |
179 | if (ctx->pmeth->copy(ret, ctx) <= 0) { |
180 | ret->pmeth = NULL; |
181 | EVP_PKEY_CTX_free(ret); |
182 | OPENSSL_PUT_ERROR(EVP, ERR_LIB_EVP); |
183 | return NULL; |
184 | } |
185 | |
186 | return ret; |
187 | } |
188 | |
189 | EVP_PKEY *EVP_PKEY_CTX_get0_pkey(EVP_PKEY_CTX *ctx) { return ctx->pkey; } |
190 | |
191 | int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype, int cmd, |
192 | int p1, void *p2) { |
193 | if (!ctx || !ctx->pmeth || !ctx->pmeth->ctrl) { |
194 | OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED); |
195 | return 0; |
196 | } |
197 | if (keytype != -1 && ctx->pmeth->pkey_id != keytype) { |
198 | OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
199 | return 0; |
200 | } |
201 | |
202 | if (ctx->operation == EVP_PKEY_OP_UNDEFINED) { |
203 | OPENSSL_PUT_ERROR(EVP, EVP_R_NO_OPERATION_SET); |
204 | return 0; |
205 | } |
206 | |
207 | if (optype != -1 && !(ctx->operation & optype)) { |
208 | OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_OPERATION); |
209 | return 0; |
210 | } |
211 | |
212 | return ctx->pmeth->ctrl(ctx, cmd, p1, p2); |
213 | } |
214 | |
215 | int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx) { |
216 | if (ctx == NULL || ctx->pmeth == NULL || |
217 | (ctx->pmeth->sign == NULL && ctx->pmeth->sign_message == NULL)) { |
218 | OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
219 | return 0; |
220 | } |
221 | |
222 | ctx->operation = EVP_PKEY_OP_SIGN; |
223 | return 1; |
224 | } |
225 | |
226 | int EVP_PKEY_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *sig_len, |
227 | const uint8_t *digest, size_t digest_len) { |
228 | if (!ctx || !ctx->pmeth || !ctx->pmeth->sign) { |
229 | OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
230 | return 0; |
231 | } |
232 | if (ctx->operation != EVP_PKEY_OP_SIGN) { |
233 | OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); |
234 | return 0; |
235 | } |
236 | return ctx->pmeth->sign(ctx, sig, sig_len, digest, digest_len); |
237 | } |
238 | |
239 | int EVP_PKEY_verify_init(EVP_PKEY_CTX *ctx) { |
240 | if (ctx == NULL || ctx->pmeth == NULL || |
241 | (ctx->pmeth->verify == NULL && ctx->pmeth->verify_message == NULL)) { |
242 | OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
243 | return 0; |
244 | } |
245 | ctx->operation = EVP_PKEY_OP_VERIFY; |
246 | return 1; |
247 | } |
248 | |
249 | int EVP_PKEY_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig, size_t sig_len, |
250 | const uint8_t *digest, size_t digest_len) { |
251 | if (!ctx || !ctx->pmeth || !ctx->pmeth->verify) { |
252 | OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
253 | return 0; |
254 | } |
255 | if (ctx->operation != EVP_PKEY_OP_VERIFY) { |
256 | OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); |
257 | return 0; |
258 | } |
259 | return ctx->pmeth->verify(ctx, sig, sig_len, digest, digest_len); |
260 | } |
261 | |
262 | int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *ctx) { |
263 | if (!ctx || !ctx->pmeth || !ctx->pmeth->encrypt) { |
264 | OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
265 | return 0; |
266 | } |
267 | ctx->operation = EVP_PKEY_OP_ENCRYPT; |
268 | return 1; |
269 | } |
270 | |
271 | int EVP_PKEY_encrypt(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen, |
272 | const uint8_t *in, size_t inlen) { |
273 | if (!ctx || !ctx->pmeth || !ctx->pmeth->encrypt) { |
274 | OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
275 | return 0; |
276 | } |
277 | if (ctx->operation != EVP_PKEY_OP_ENCRYPT) { |
278 | OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); |
279 | return 0; |
280 | } |
281 | return ctx->pmeth->encrypt(ctx, out, outlen, in, inlen); |
282 | } |
283 | |
284 | int EVP_PKEY_decrypt_init(EVP_PKEY_CTX *ctx) { |
285 | if (!ctx || !ctx->pmeth || !ctx->pmeth->decrypt) { |
286 | OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
287 | return 0; |
288 | } |
289 | ctx->operation = EVP_PKEY_OP_DECRYPT; |
290 | return 1; |
291 | } |
292 | |
293 | int EVP_PKEY_decrypt(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen, |
294 | const uint8_t *in, size_t inlen) { |
295 | if (!ctx || !ctx->pmeth || !ctx->pmeth->decrypt) { |
296 | OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
297 | return 0; |
298 | } |
299 | if (ctx->operation != EVP_PKEY_OP_DECRYPT) { |
300 | OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); |
301 | return 0; |
302 | } |
303 | return ctx->pmeth->decrypt(ctx, out, outlen, in, inlen); |
304 | } |
305 | |
306 | int EVP_PKEY_verify_recover_init(EVP_PKEY_CTX *ctx) { |
307 | if (!ctx || !ctx->pmeth || !ctx->pmeth->verify_recover) { |
308 | OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
309 | return 0; |
310 | } |
311 | ctx->operation = EVP_PKEY_OP_VERIFYRECOVER; |
312 | return 1; |
313 | } |
314 | |
315 | int EVP_PKEY_verify_recover(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *out_len, |
316 | const uint8_t *sig, size_t sig_len) { |
317 | if (!ctx || !ctx->pmeth || !ctx->pmeth->verify_recover) { |
318 | OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
319 | return 0; |
320 | } |
321 | if (ctx->operation != EVP_PKEY_OP_VERIFYRECOVER) { |
322 | OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); |
323 | return 0; |
324 | } |
325 | return ctx->pmeth->verify_recover(ctx, out, out_len, sig, sig_len); |
326 | } |
327 | |
328 | int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx) { |
329 | if (!ctx || !ctx->pmeth || !ctx->pmeth->derive) { |
330 | OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
331 | return 0; |
332 | } |
333 | ctx->operation = EVP_PKEY_OP_DERIVE; |
334 | return 1; |
335 | } |
336 | |
337 | int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer) { |
338 | int ret; |
339 | if (!ctx || !ctx->pmeth || |
340 | !(ctx->pmeth->derive || ctx->pmeth->encrypt || ctx->pmeth->decrypt) || |
341 | !ctx->pmeth->ctrl) { |
342 | OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
343 | return 0; |
344 | } |
345 | if (ctx->operation != EVP_PKEY_OP_DERIVE && |
346 | ctx->operation != EVP_PKEY_OP_ENCRYPT && |
347 | ctx->operation != EVP_PKEY_OP_DECRYPT) { |
348 | OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); |
349 | return 0; |
350 | } |
351 | |
352 | ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 0, peer); |
353 | |
354 | if (ret <= 0) { |
355 | return 0; |
356 | } |
357 | |
358 | if (ret == 2) { |
359 | return 1; |
360 | } |
361 | |
362 | if (!ctx->pkey) { |
363 | OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET); |
364 | return 0; |
365 | } |
366 | |
367 | if (ctx->pkey->type != peer->type) { |
368 | OPENSSL_PUT_ERROR(EVP, EVP_R_DIFFERENT_KEY_TYPES); |
369 | return 0; |
370 | } |
371 | |
372 | // ran@cryptocom.ru: For clarity. The error is if parameters in peer are |
373 | // present (!missing) but don't match. EVP_PKEY_cmp_parameters may return |
374 | // 1 (match), 0 (don't match) and -2 (comparison is not defined). -1 |
375 | // (different key types) is impossible here because it is checked earlier. |
376 | // -2 is OK for us here, as well as 1, so we can check for 0 only. |
377 | if (!EVP_PKEY_missing_parameters(peer) && |
378 | !EVP_PKEY_cmp_parameters(ctx->pkey, peer)) { |
379 | OPENSSL_PUT_ERROR(EVP, EVP_R_DIFFERENT_PARAMETERS); |
380 | return 0; |
381 | } |
382 | |
383 | EVP_PKEY_free(ctx->peerkey); |
384 | ctx->peerkey = peer; |
385 | |
386 | ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 1, peer); |
387 | |
388 | if (ret <= 0) { |
389 | ctx->peerkey = NULL; |
390 | return 0; |
391 | } |
392 | |
393 | EVP_PKEY_up_ref(peer); |
394 | return 1; |
395 | } |
396 | |
397 | int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, uint8_t *key, size_t *out_key_len) { |
398 | if (!ctx || !ctx->pmeth || !ctx->pmeth->derive) { |
399 | OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
400 | return 0; |
401 | } |
402 | if (ctx->operation != EVP_PKEY_OP_DERIVE) { |
403 | OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); |
404 | return 0; |
405 | } |
406 | return ctx->pmeth->derive(ctx, key, out_key_len); |
407 | } |
408 | |
409 | int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx) { |
410 | if (!ctx || !ctx->pmeth || !ctx->pmeth->keygen) { |
411 | OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
412 | return 0; |
413 | } |
414 | ctx->operation = EVP_PKEY_OP_KEYGEN; |
415 | return 1; |
416 | } |
417 | |
418 | int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **out_pkey) { |
419 | if (!ctx || !ctx->pmeth || !ctx->pmeth->keygen) { |
420 | OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
421 | return 0; |
422 | } |
423 | if (ctx->operation != EVP_PKEY_OP_KEYGEN) { |
424 | OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); |
425 | return 0; |
426 | } |
427 | |
428 | if (!out_pkey) { |
429 | return 0; |
430 | } |
431 | |
432 | if (!*out_pkey) { |
433 | *out_pkey = EVP_PKEY_new(); |
434 | if (!*out_pkey) { |
435 | OPENSSL_PUT_ERROR(EVP, ERR_LIB_EVP); |
436 | return 0; |
437 | } |
438 | } |
439 | |
440 | if (!ctx->pmeth->keygen(ctx, *out_pkey)) { |
441 | EVP_PKEY_free(*out_pkey); |
442 | *out_pkey = NULL; |
443 | return 0; |
444 | } |
445 | return 1; |
446 | } |
447 | |
448 | int EVP_PKEY_paramgen_init(EVP_PKEY_CTX *ctx) { |
449 | if (!ctx || !ctx->pmeth || !ctx->pmeth->paramgen) { |
450 | OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
451 | return 0; |
452 | } |
453 | ctx->operation = EVP_PKEY_OP_PARAMGEN; |
454 | return 1; |
455 | } |
456 | |
457 | int EVP_PKEY_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY **out_pkey) { |
458 | if (!ctx || !ctx->pmeth || !ctx->pmeth->paramgen) { |
459 | OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); |
460 | return 0; |
461 | } |
462 | if (ctx->operation != EVP_PKEY_OP_PARAMGEN) { |
463 | OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); |
464 | return 0; |
465 | } |
466 | |
467 | if (!out_pkey) { |
468 | return 0; |
469 | } |
470 | |
471 | if (!*out_pkey) { |
472 | *out_pkey = EVP_PKEY_new(); |
473 | if (!*out_pkey) { |
474 | OPENSSL_PUT_ERROR(EVP, ERR_LIB_EVP); |
475 | return 0; |
476 | } |
477 | } |
478 | |
479 | if (!ctx->pmeth->paramgen(ctx, *out_pkey)) { |
480 | EVP_PKEY_free(*out_pkey); |
481 | *out_pkey = NULL; |
482 | return 0; |
483 | } |
484 | return 1; |
485 | } |
486 | |