]> git.ipfire.org Git - thirdparty/openssl.git/blame - crypto/x509/x_pubkey.c
apps/lib/opt.c: Fix error message on unknown option/digest
[thirdparty/openssl.git] / crypto / x509 / x_pubkey.c
CommitLineData
b1322259 1/*
33388b44 2 * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
d02b48c6 3 *
3e4b43b9 4 * Licensed under the Apache License 2.0 (the "License"). You may not use
b1322259
RS
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
d02b48c6
RE
8 */
9
f41ac0ee
P
10/*
11 * DSA low level APIs are deprecated for public use, but still ok for
12 * internal use.
13 */
14#include "internal/deprecated.h"
15
d02b48c6 16#include <stdio.h>
b39fc560 17#include "internal/cryptlib.h"
9d6b1ce6 18#include <openssl/asn1t.h>
f0e8ae72 19#include <openssl/x509.h>
25f2138b
DMSP
20#include "crypto/asn1.h"
21#include "crypto/evp.h"
22#include "crypto/x509.h"
3c27208f
RS
23#include <openssl/rsa.h>
24#include <openssl/dsa.h>
ece9304c 25#include <openssl/encoder.h>
97bb8dff 26#include "internal/provider.h"
d02b48c6 27
29fa0a1a
DSH
28struct X509_pubkey_st {
29 X509_ALGOR *algor;
30 ASN1_BIT_STRING *public_key;
31 EVP_PKEY *pkey;
22b81444
RL
32
33 /* extra data for the callback, used by d2i_PUBKEY_ex */
b4250010 34 OSSL_LIB_CTX *libctx;
637dce3c 35 char *propq;
29fa0a1a
DSH
36};
37
7674e923 38static int x509_pubkey_decode(EVP_PKEY **pk, const X509_PUBKEY *key);
fa0a9d71 39
637dce3c
SL
40static int x509_pubkey_set0_libctx(X509_PUBKEY *x, OSSL_LIB_CTX *libctx,
41 const char *propq)
42{
43 if (x != NULL) {
44 x->libctx = libctx;
45 OPENSSL_free(x->propq);
46 x->propq = NULL;
47 if (propq != NULL) {
48 x->propq = OPENSSL_strdup(propq);
49 if (x->propq == NULL)
50 return 0;
51 }
52 }
53 return 1;
54}
55
9d6b1ce6 56/* Minor tweak to operation: free up EVP_PKEY */
24484759 57static int pubkey_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
0f113f3e
MC
58 void *exarg)
59{
66066e1b
DDO
60 X509_PUBKEY *pubkey = (X509_PUBKEY *)*pval;
61
0f113f3e 62 if (operation == ASN1_OP_FREE_POST) {
637dce3c 63 OPENSSL_free(pubkey->propq);
0f113f3e 64 EVP_PKEY_free(pubkey->pkey);
d2ec189f
DSH
65 } else if (operation == ASN1_OP_D2I_POST) {
66 /* Attempt to decode public key and cache in pubkey structure. */
d2ec189f 67 EVP_PKEY_free(pubkey->pkey);
5dc40a83 68 pubkey->pkey = NULL;
d2ec189f 69 /*
fa0a9d71
DSH
70 * Opportunistically decode the key but remove any non fatal errors
71 * from the queue. Subsequent explicit attempts to decode/use the key
72 * will return an appropriate error.
d2ec189f
DSH
73 */
74 ERR_set_mark();
66066e1b
DDO
75 if (x509_pubkey_decode(&pubkey->pkey, pubkey) == -1) {
76 ERR_clear_last_mark();
fa0a9d71 77 return 0;
66066e1b 78 }
d2ec189f 79 ERR_pop_to_mark();
637dce3c
SL
80 } else if (operation == ASN1_OP_DUP_POST) {
81 X509_PUBKEY *old = exarg;
82
83 if (!x509_pubkey_set0_libctx(pubkey, old->libctx, old->propq))
84 return 0;
0f113f3e
MC
85 }
86 return 1;
87}
d02b48c6 88
9d6b1ce6 89ASN1_SEQUENCE_cb(X509_PUBKEY, pubkey_cb) = {
0f113f3e
MC
90 ASN1_SIMPLE(X509_PUBKEY, algor, X509_ALGOR),
91 ASN1_SIMPLE(X509_PUBKEY, public_key, ASN1_BIT_STRING)
d339187b 92} ASN1_SEQUENCE_END_cb(X509_PUBKEY, X509_PUBKEY)
d02b48c6 93
9d6b1ce6 94IMPLEMENT_ASN1_FUNCTIONS(X509_PUBKEY)
a8f1aabd 95IMPLEMENT_ASN1_DUP_FUNCTION(X509_PUBKEY)
d02b48c6 96
9fdcc21f 97/* TODO should better be called X509_PUBKEY_set1 */
6b691a5c 98int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey)
0f113f3e
MC
99{
100 X509_PUBKEY *pk = NULL;
101
102 if (x == NULL)
26a7d938 103 return 0;
0f113f3e 104
e56ba0e1
RL
105 if (pkey == NULL)
106 goto unsupported;
0f113f3e 107
e56ba0e1
RL
108 if (pkey->ameth != NULL) {
109 if ((pk = X509_PUBKEY_new()) == NULL) {
9311d0c4 110 ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
e56ba0e1
RL
111 goto error;
112 }
113 if (pkey->ameth->pub_encode != NULL) {
0f113f3e 114 if (!pkey->ameth->pub_encode(pk, pkey)) {
9311d0c4 115 ERR_raise(ERR_LIB_X509, X509_R_PUBLIC_KEY_ENCODE_ERROR);
0f113f3e
MC
116 goto error;
117 }
118 } else {
9311d0c4 119 ERR_raise(ERR_LIB_X509, X509_R_METHOD_NOT_SUPPORTED);
0f113f3e
MC
120 goto error;
121 }
113adc1f 122 } else if (evp_pkey_is_provided(pkey)) {
113adc1f
RL
123 unsigned char *der = NULL;
124 size_t derlen = 0;
ece9304c 125 OSSL_ENCODER_CTX *ectx =
4227e504
RL
126 OSSL_ENCODER_CTX_new_by_EVP_PKEY(pkey, EVP_PKEY_PUBLIC_KEY,
127 "DER", "SubjectPublicKeyInfo",
b03da688 128 NULL);
e56ba0e1 129
113adc1f
RL
130 if (OSSL_ENCODER_to_data(ectx, &der, &derlen)) {
131 const unsigned char *pder = der;
e56ba0e1 132
113adc1f 133 pk = d2i_X509_PUBKEY(NULL, &pder, (long)derlen);
e56ba0e1
RL
134 }
135
ece9304c 136 OSSL_ENCODER_CTX_free(ectx);
113adc1f 137 OPENSSL_free(der);
0f113f3e
MC
138 }
139
e56ba0e1
RL
140 if (pk == NULL)
141 goto unsupported;
142
222561fe 143 X509_PUBKEY_free(*x);
e56ba0e1 144 if (!EVP_PKEY_up_ref(pkey)) {
9311d0c4 145 ERR_raise(ERR_LIB_X509, ERR_R_INTERNAL_ERROR);
e56ba0e1
RL
146 goto error;
147 }
0f113f3e 148 *x = pk;
a076951b
RL
149
150 /*
151 * pk->pkey is NULL when using the legacy routine, but is non-NULL when
ece9304c 152 * going through the encoder, and for all intents and purposes, it's
a076951b
RL
153 * a perfect copy of |pkey|, just not the same instance. In that case,
154 * we could simply return early, right here.
155 * However, in the interest of being cautious leaning on paranoia, some
156 * application might very well depend on the passed |pkey| being used
157 * and none other, so we spend a few more cycles throwing away the newly
158 * created |pk->pkey| and replace it with |pkey|.
159 * TODO(3.0) Investigate if it's safe to change to simply return here
160 * if |pk->pkey != NULL|.
161 */
162 if (pk->pkey != NULL)
163 EVP_PKEY_free(pk->pkey);
164
fa0a9d71 165 pk->pkey = pkey;
e56ba0e1
RL
166 return 1;
167
168 unsupported:
9311d0c4 169 ERR_raise(ERR_LIB_X509, X509_R_UNSUPPORTED_ALGORITHM);
222561fe 170
0f113f3e 171 error:
222561fe 172 X509_PUBKEY_free(pk);
0f113f3e
MC
173 return 0;
174}
d02b48c6 175
fa0a9d71
DSH
176/*
177 * Attempt to decode a public key.
178 * Returns 1 on success, 0 for a decode failure and -1 for a fatal
179 * error e.g. malloc failure.
180 */
0f113f3e 181
0f113f3e 182
7674e923 183static int x509_pubkey_decode(EVP_PKEY **ppkey, const X509_PUBKEY *key)
7fcdbd83 184{
fa0a9d71 185 EVP_PKEY *pkey = EVP_PKEY_new();
0f113f3e 186
fa0a9d71 187 if (pkey == NULL) {
9311d0c4 188 ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
fa0a9d71 189 return -1;
0f113f3e
MC
190 }
191
fa0a9d71 192 if (!EVP_PKEY_set_type(pkey, OBJ_obj2nid(key->algor->algorithm))) {
9311d0c4 193 ERR_raise(ERR_LIB_X509, X509_R_UNSUPPORTED_ALGORITHM);
0f113f3e
MC
194 goto error;
195 }
196
fa0a9d71
DSH
197 if (pkey->ameth->pub_decode) {
198 /*
199 * Treat any failure of pub_decode as a decode error. In
200 * future we could have different return codes for decode
201 * errors and fatal errors such as malloc failure.
202 */
66066e1b 203 if (!pkey->ameth->pub_decode(pkey, key))
0f113f3e 204 goto error;
0f113f3e 205 } else {
9311d0c4 206 ERR_raise(ERR_LIB_X509, X509_R_METHOD_NOT_SUPPORTED);
0f113f3e
MC
207 goto error;
208 }
209
fa0a9d71
DSH
210 *ppkey = pkey;
211 return 1;
0f113f3e
MC
212
213 error:
fa0a9d71
DSH
214 EVP_PKEY_free(pkey);
215 return 0;
216}
217
7674e923 218EVP_PKEY *X509_PUBKEY_get0(const X509_PUBKEY *key)
fa0a9d71
DSH
219{
220 EVP_PKEY *ret = NULL;
221
222 if (key == NULL || key->public_key == NULL)
223 return NULL;
224
225 if (key->pkey != NULL)
226 return key->pkey;
227
228 /*
229 * When the key ASN.1 is initially parsed an attempt is made to
230 * decode the public key and cache the EVP_PKEY structure. If this
231 * operation fails the cached value will be NULL. Parsing continues
232 * to allow parsing of unknown key types or unsupported forms.
233 * We repeat the decode operation so the appropriate errors are left
234 * in the queue.
235 */
236 x509_pubkey_decode(&ret, key);
237 /* If decode doesn't fail something bad happened */
238 if (ret != NULL) {
9311d0c4 239 ERR_raise(ERR_LIB_X509, ERR_R_INTERNAL_ERROR);
fa0a9d71
DSH
240 EVP_PKEY_free(ret);
241 }
242
243 return NULL;
0f113f3e
MC
244}
245
7674e923 246EVP_PKEY *X509_PUBKEY_get(const X509_PUBKEY *key)
c01ff880
DSH
247{
248 EVP_PKEY *ret = X509_PUBKEY_get0(key);
e9e7b5df
BE
249
250 if (ret != NULL && !EVP_PKEY_up_ref(ret)) {
9311d0c4 251 ERR_raise(ERR_LIB_X509, ERR_R_INTERNAL_ERROR);
e9e7b5df
BE
252 ret = NULL;
253 }
c01ff880
DSH
254 return ret;
255}
256
0f113f3e 257/*
22b81444
RL
258 * Now three pseudo ASN1 routines that take an EVP_PKEY structure and encode
259 * or decode as X509_PUBKEY
52664f50
DSH
260 */
261
22b81444 262EVP_PKEY *d2i_PUBKEY_ex(EVP_PKEY **a, const unsigned char **pp, long length,
b4250010 263 OSSL_LIB_CTX *libctx, const char *propq)
0f113f3e 264{
22b81444
RL
265 X509_PUBKEY *xpk, *xpk2 = NULL, **pxpk = NULL;
266 EVP_PKEY *pktmp = NULL;
a46c9789 267 const unsigned char *q;
12a765a5 268
a46c9789 269 q = *pp;
22b81444
RL
270
271 /*
272 * If libctx or propq are non-NULL, we take advantage of the reuse
273 * feature. It's not generally recommended, but is safe enough for
274 * newly created structures.
275 */
276 if (libctx != NULL || propq != NULL) {
277 xpk2 = OPENSSL_zalloc(sizeof(*xpk2));
278 if (xpk2 == NULL) {
279 ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
280 return NULL;
281 }
637dce3c
SL
282 if (!x509_pubkey_set0_libctx(xpk2, libctx, propq))
283 goto end;
22b81444
RL
284 pxpk = &xpk2;
285 }
286 xpk = d2i_X509_PUBKEY(pxpk, &q, length);
12a765a5 287 if (xpk == NULL)
22b81444 288 goto end;
0f113f3e
MC
289 pktmp = X509_PUBKEY_get(xpk);
290 X509_PUBKEY_free(xpk);
22b81444 291 xpk2 = NULL; /* We know that xpk == xpk2 */
12a765a5 292 if (pktmp == NULL)
22b81444 293 goto end;
a46c9789 294 *pp = q;
12a765a5 295 if (a != NULL) {
0f113f3e
MC
296 EVP_PKEY_free(*a);
297 *a = pktmp;
298 }
22b81444
RL
299 end:
300 X509_PUBKEY_free(xpk2);
0f113f3e
MC
301 return pktmp;
302}
52664f50 303
22b81444
RL
304EVP_PKEY *d2i_PUBKEY(EVP_PKEY **a, const unsigned char **pp, long length)
305{
306 return d2i_PUBKEY_ex(a, pp, length, NULL, NULL);
307}
308
9fdcc21f 309int i2d_PUBKEY(const EVP_PKEY *a, unsigned char **pp)
0f113f3e 310{
9fdcc21f
DO
311 int ret = -1;
312
313 if (a == NULL)
0f113f3e 314 return 0;
cdb16632
RL
315 if (a->ameth != NULL) {
316 X509_PUBKEY *xpk = NULL;
317
318 if ((xpk = X509_PUBKEY_new()) == NULL)
319 return -1;
320
321 /* pub_encode() only encode parameters, not the key itself */
322 if (a->ameth->pub_encode != NULL && a->ameth->pub_encode(xpk, a)) {
323 xpk->pkey = (EVP_PKEY *)a;
324 ret = i2d_X509_PUBKEY(xpk, pp);
325 xpk->pkey = NULL;
326 }
327 X509_PUBKEY_free(xpk);
3c6ed955 328 } else if (a->keymgmt != NULL) {
ece9304c 329 OSSL_ENCODER_CTX *ctx =
4227e504
RL
330 OSSL_ENCODER_CTX_new_by_EVP_PKEY(a, EVP_PKEY_PUBLIC_KEY,
331 "DER", "SubjectPublicKeyInfo",
b03da688 332 NULL);
cdb16632
RL
333 BIO *out = BIO_new(BIO_s_mem());
334 BUF_MEM *buf = NULL;
335
97bb8dff 336 if (OSSL_ENCODER_CTX_get_num_encoders(ctx) != 0
cdb16632 337 && out != NULL
ece9304c 338 && OSSL_ENCODER_to_bio(ctx, out)
cdb16632
RL
339 && BIO_get_mem_ptr(out, &buf) > 0) {
340 ret = buf->length;
341
342 if (pp != NULL) {
343 if (*pp == NULL) {
344 *pp = (unsigned char *)buf->data;
345 buf->length = 0;
346 buf->data = NULL;
347 } else {
348 memcpy(*pp, buf->data, ret);
349 *pp += ret;
350 }
351 }
352 }
353 BIO_free(out);
ece9304c 354 OSSL_ENCODER_CTX_free(ctx);
cdb16632
RL
355 }
356
0f113f3e
MC
357 return ret;
358}
359
360/*
361 * The following are equivalents but which return RSA and DSA keys
52664f50 362 */
0f113f3e
MC
363RSA *d2i_RSA_PUBKEY(RSA **a, const unsigned char **pp, long length)
364{
365 EVP_PKEY *pkey;
366 RSA *key;
367 const unsigned char *q;
12a765a5 368
0f113f3e
MC
369 q = *pp;
370 pkey = d2i_PUBKEY(NULL, &q, length);
12a765a5 371 if (pkey == NULL)
0f113f3e
MC
372 return NULL;
373 key = EVP_PKEY_get1_RSA(pkey);
374 EVP_PKEY_free(pkey);
12a765a5 375 if (key == NULL)
0f113f3e
MC
376 return NULL;
377 *pp = q;
12a765a5 378 if (a != NULL) {
0f113f3e
MC
379 RSA_free(*a);
380 *a = key;
381 }
382 return key;
383}
52664f50 384
9fdcc21f 385int i2d_RSA_PUBKEY(const RSA *a, unsigned char **pp)
0f113f3e
MC
386{
387 EVP_PKEY *pktmp;
388 int ret;
389 if (!a)
390 return 0;
391 pktmp = EVP_PKEY_new();
90945fa3 392 if (pktmp == NULL) {
9311d0c4 393 ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
157997f0 394 return -1;
0f113f3e 395 }
9fdcc21f 396 (void)EVP_PKEY_assign_RSA(pktmp, (RSA *)a);
0f113f3e 397 ret = i2d_PUBKEY(pktmp, pp);
9fdcc21f 398 pktmp->pkey.ptr = NULL;
0f113f3e
MC
399 EVP_PKEY_free(pktmp);
400 return ret;
401}
52664f50 402
cf1b7d96 403#ifndef OPENSSL_NO_DSA
0f113f3e
MC
404DSA *d2i_DSA_PUBKEY(DSA **a, const unsigned char **pp, long length)
405{
406 EVP_PKEY *pkey;
407 DSA *key;
408 const unsigned char *q;
12a765a5 409
0f113f3e
MC
410 q = *pp;
411 pkey = d2i_PUBKEY(NULL, &q, length);
12a765a5 412 if (pkey == NULL)
0f113f3e
MC
413 return NULL;
414 key = EVP_PKEY_get1_DSA(pkey);
415 EVP_PKEY_free(pkey);
12a765a5 416 if (key == NULL)
0f113f3e
MC
417 return NULL;
418 *pp = q;
12a765a5 419 if (a != NULL) {
0f113f3e
MC
420 DSA_free(*a);
421 *a = key;
422 }
423 return key;
424}
52664f50 425
9fdcc21f 426int i2d_DSA_PUBKEY(const DSA *a, unsigned char **pp)
0f113f3e
MC
427{
428 EVP_PKEY *pktmp;
429 int ret;
430 if (!a)
431 return 0;
432 pktmp = EVP_PKEY_new();
90945fa3 433 if (pktmp == NULL) {
9311d0c4 434 ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
157997f0 435 return -1;
0f113f3e 436 }
9fdcc21f 437 (void)EVP_PKEY_assign_DSA(pktmp, (DSA *)a);
0f113f3e 438 ret = i2d_PUBKEY(pktmp, pp);
9fdcc21f 439 pktmp->pkey.ptr = NULL;
0f113f3e
MC
440 EVP_PKEY_free(pktmp);
441 return ret;
442}
4d94ae00
BM
443#endif
444
14a7cfb3 445#ifndef OPENSSL_NO_EC
6343829a 446EC_KEY *d2i_EC_PUBKEY(EC_KEY **a, const unsigned char **pp, long length)
0f113f3e
MC
447{
448 EVP_PKEY *pkey;
449 EC_KEY *key;
450 const unsigned char *q;
12a765a5 451
0f113f3e
MC
452 q = *pp;
453 pkey = d2i_PUBKEY(NULL, &q, length);
12a765a5 454 if (pkey == NULL)
26a7d938 455 return NULL;
0f113f3e
MC
456 key = EVP_PKEY_get1_EC_KEY(pkey);
457 EVP_PKEY_free(pkey);
12a765a5 458 if (key == NULL)
26a7d938 459 return NULL;
0f113f3e 460 *pp = q;
12a765a5 461 if (a != NULL) {
0f113f3e
MC
462 EC_KEY_free(*a);
463 *a = key;
464 }
26a7d938 465 return key;
0f113f3e 466}
4d94ae00 467
9fdcc21f 468int i2d_EC_PUBKEY(const EC_KEY *a, unsigned char **pp)
0f113f3e
MC
469{
470 EVP_PKEY *pktmp;
471 int ret;
12a765a5
RS
472
473 if (a == NULL)
26a7d938 474 return 0;
0f113f3e 475 if ((pktmp = EVP_PKEY_new()) == NULL) {
9311d0c4 476 ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
157997f0 477 return -1;
0f113f3e 478 }
9fdcc21f 479 (void)EVP_PKEY_assign_EC_KEY(pktmp, (EC_KEY *)a);
0f113f3e 480 ret = i2d_PUBKEY(pktmp, pp);
9fdcc21f 481 pktmp->pkey.ptr = NULL;
0f113f3e 482 EVP_PKEY_free(pktmp);
26a7d938 483 return ret;
0f113f3e 484}
12aefe78 485#endif
448be743
DSH
486
487int X509_PUBKEY_set0_param(X509_PUBKEY *pub, ASN1_OBJECT *aobj,
0f113f3e
MC
488 int ptype, void *pval,
489 unsigned char *penc, int penclen)
490{
491 if (!X509_ALGOR_set0(pub->algor, aobj, ptype, pval))
492 return 0;
493 if (penc) {
b548a1f1 494 OPENSSL_free(pub->public_key->data);
0f113f3e
MC
495 pub->public_key->data = penc;
496 pub->public_key->length = penclen;
497 /* Set number of unused bits to zero */
498 pub->public_key->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
499 pub->public_key->flags |= ASN1_STRING_FLAG_BITS_LEFT;
500 }
501 return 1;
502}
448be743
DSH
503
504int X509_PUBKEY_get0_param(ASN1_OBJECT **ppkalg,
0f113f3e 505 const unsigned char **pk, int *ppklen,
7674e923 506 X509_ALGOR **pa, const X509_PUBKEY *pub)
0f113f3e
MC
507{
508 if (ppkalg)
509 *ppkalg = pub->algor->algorithm;
510 if (pk) {
511 *pk = pub->public_key->data;
512 *ppklen = pub->public_key->length;
513 }
514 if (pa)
515 *pa = pub->algor;
516 return 1;
517}
29fa0a1a
DSH
518
519ASN1_BIT_STRING *X509_get0_pubkey_bitstr(const X509 *x)
520{
521 if (x == NULL)
522 return NULL;
523 return x->cert_info.key->public_key;
524}
93f99b68
DDO
525
526/* Returns 1 for equal, 0, for non-equal, < 0 on error */
527int X509_PUBKEY_eq(const X509_PUBKEY *a, const X509_PUBKEY *b)
528{
529 X509_ALGOR *algA, *algB;
530 EVP_PKEY *pA, *pB;
531
532 if (a == b)
533 return 1;
534 if (a == NULL || b == NULL)
535 return 0;
536 if (!X509_PUBKEY_get0_param(NULL, NULL, NULL, &algA, a) || algA == NULL
537 || !X509_PUBKEY_get0_param(NULL, NULL, NULL, &algB, b) || algB == NULL)
538 return -2;
539 if (X509_ALGOR_cmp(algA, algB) != 0)
540 return 0;
541 if ((pA = X509_PUBKEY_get0(a)) == NULL
542 || (pB = X509_PUBKEY_get0(b)) == NULL)
543 return -2;
c74aaa39 544 return EVP_PKEY_eq(pA, pB);
93f99b68 545}
22b81444 546
b4250010 547int X509_PUBKEY_get0_libctx(OSSL_LIB_CTX **plibctx, const char **ppropq,
22b81444
RL
548 const X509_PUBKEY *key)
549{
550 if (plibctx)
551 *plibctx = key->libctx;
552 if (ppropq)
553 *ppropq = key->propq;
554 return 1;
555}