xref: /freebsd/crypto/openssl/crypto/x509/x509_req.c (revision e0c4386e)
1e71b7053SJung-uk Kim /*
2e0c4386eSCy Schubert  * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
374664626SKris Kennaway  *
4b077aed3SPierre Pronchery  * Licensed under the Apache License 2.0 (the "License").  You may not use
5e71b7053SJung-uk Kim  * this file except in compliance with the License.  You can obtain a copy
6e71b7053SJung-uk Kim  * in the file LICENSE in the source distribution or at
7e71b7053SJung-uk Kim  * https://www.openssl.org/source/license.html
874664626SKris Kennaway  */
974664626SKris Kennaway 
1074664626SKris Kennaway #include <stdio.h>
11e71b7053SJung-uk Kim #include "internal/cryptlib.h"
1274664626SKris Kennaway #include <openssl/bn.h>
1374664626SKris Kennaway #include <openssl/evp.h>
1474664626SKris Kennaway #include <openssl/asn1.h>
151f13597dSJung-uk Kim #include <openssl/asn1t.h>
1674664626SKris Kennaway #include <openssl/x509.h>
1717f01e99SJung-uk Kim #include "crypto/x509.h"
1874664626SKris Kennaway #include <openssl/objects.h>
1974664626SKris Kennaway #include <openssl/buffer.h>
2074664626SKris Kennaway #include <openssl/pem.h>
2174664626SKris Kennaway 
X509_to_X509_REQ(X509 * x,EVP_PKEY * pkey,const EVP_MD * md)22f579bf8eSKris Kennaway X509_REQ *X509_to_X509_REQ(X509 *x, EVP_PKEY *pkey, const EVP_MD *md)
2374664626SKris Kennaway {
2474664626SKris Kennaway     X509_REQ *ret;
2574664626SKris Kennaway     X509_REQ_INFO *ri;
2674664626SKris Kennaway     int i;
2774664626SKris Kennaway     EVP_PKEY *pktmp;
2874664626SKris Kennaway 
29b077aed3SPierre Pronchery     ret = X509_REQ_new_ex(x->libctx, x->propq);
306f9291ceSJung-uk Kim     if (ret == NULL) {
31b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
3274664626SKris Kennaway         goto err;
3374664626SKris Kennaway     }
3474664626SKris Kennaway 
35e71b7053SJung-uk Kim     ri = &ret->req_info;
3674664626SKris Kennaway 
3774664626SKris Kennaway     ri->version->length = 1;
38e71b7053SJung-uk Kim     ri->version->data = OPENSSL_malloc(1);
396f9291ceSJung-uk Kim     if (ri->version->data == NULL)
406f9291ceSJung-uk Kim         goto err;
4174664626SKris Kennaway     ri->version->data[0] = 0;   /* version == 0 */
4274664626SKris Kennaway 
4374664626SKris Kennaway     if (!X509_REQ_set_subject_name(ret, X509_get_subject_name(x)))
4474664626SKris Kennaway         goto err;
4574664626SKris Kennaway 
46e71b7053SJung-uk Kim     pktmp = X509_get0_pubkey(x);
476f9291ceSJung-uk Kim     if (pktmp == NULL)
486f9291ceSJung-uk Kim         goto err;
4974664626SKris Kennaway     i = X509_REQ_set_pubkey(ret, pktmp);
506f9291ceSJung-uk Kim     if (!i)
516f9291ceSJung-uk Kim         goto err;
5274664626SKris Kennaway 
536f9291ceSJung-uk Kim     if (pkey != NULL) {
5474664626SKris Kennaway         if (!X509_REQ_sign(ret, pkey, md))
5574664626SKris Kennaway             goto err;
5674664626SKris Kennaway     }
57e71b7053SJung-uk Kim     return ret;
5874664626SKris Kennaway  err:
5974664626SKris Kennaway     X509_REQ_free(ret);
60e71b7053SJung-uk Kim     return NULL;
6174664626SKris Kennaway }
6274664626SKris Kennaway 
X509_REQ_get_pubkey(X509_REQ * req)6374664626SKris Kennaway EVP_PKEY *X509_REQ_get_pubkey(X509_REQ *req)
6474664626SKris Kennaway {
65e71b7053SJung-uk Kim     if (req == NULL)
66e71b7053SJung-uk Kim         return NULL;
67e71b7053SJung-uk Kim     return X509_PUBKEY_get(req->req_info.pubkey);
68e71b7053SJung-uk Kim }
69e71b7053SJung-uk Kim 
X509_REQ_get0_pubkey(X509_REQ * req)70e71b7053SJung-uk Kim EVP_PKEY *X509_REQ_get0_pubkey(X509_REQ *req)
71e71b7053SJung-uk Kim {
72e71b7053SJung-uk Kim     if (req == NULL)
73e71b7053SJung-uk Kim         return NULL;
74e71b7053SJung-uk Kim     return X509_PUBKEY_get0(req->req_info.pubkey);
75e71b7053SJung-uk Kim }
76e71b7053SJung-uk Kim 
X509_REQ_get_X509_PUBKEY(X509_REQ * req)77e71b7053SJung-uk Kim X509_PUBKEY *X509_REQ_get_X509_PUBKEY(X509_REQ *req)
78e71b7053SJung-uk Kim {
79e71b7053SJung-uk Kim     return req->req_info.pubkey;
8074664626SKris Kennaway }
8174664626SKris Kennaway 
X509_REQ_check_private_key(X509_REQ * x,EVP_PKEY * k)823b4e3dcbSSimon L. B. Nielsen int X509_REQ_check_private_key(X509_REQ *x, EVP_PKEY *k)
833b4e3dcbSSimon L. B. Nielsen {
843b4e3dcbSSimon L. B. Nielsen     EVP_PKEY *xk = NULL;
853b4e3dcbSSimon L. B. Nielsen     int ok = 0;
863b4e3dcbSSimon L. B. Nielsen 
873b4e3dcbSSimon L. B. Nielsen     xk = X509_REQ_get_pubkey(x);
88b077aed3SPierre Pronchery     switch (EVP_PKEY_eq(xk, k)) {
893b4e3dcbSSimon L. B. Nielsen     case 1:
903b4e3dcbSSimon L. B. Nielsen         ok = 1;
913b4e3dcbSSimon L. B. Nielsen         break;
923b4e3dcbSSimon L. B. Nielsen     case 0:
93b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_X509, X509_R_KEY_VALUES_MISMATCH);
943b4e3dcbSSimon L. B. Nielsen         break;
953b4e3dcbSSimon L. B. Nielsen     case -1:
96b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_X509, X509_R_KEY_TYPE_MISMATCH);
973b4e3dcbSSimon L. B. Nielsen         break;
983b4e3dcbSSimon L. B. Nielsen     case -2:
99b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_X509, X509_R_UNKNOWN_KEY_TYPE);
1003b4e3dcbSSimon L. B. Nielsen     }
1013b4e3dcbSSimon L. B. Nielsen 
1023b4e3dcbSSimon L. B. Nielsen     EVP_PKEY_free(xk);
103e71b7053SJung-uk Kim     return ok;
1043b4e3dcbSSimon L. B. Nielsen }
1053b4e3dcbSSimon L. B. Nielsen 
1066f9291ceSJung-uk Kim /*
1076f9291ceSJung-uk Kim  * It seems several organisations had the same idea of including a list of
108f579bf8eSKris Kennaway  * extensions in a certificate request. There are at least two OIDs that are
109f579bf8eSKris Kennaway  * used and there may be more: so the list is configurable.
110f579bf8eSKris Kennaway  */
111f579bf8eSKris Kennaway 
1126be8ae07SJacques Vidrine static int ext_nid_list[] = { NID_ext_req, NID_ms_ext_req, NID_undef };
113f579bf8eSKris Kennaway 
114f579bf8eSKris Kennaway static int *ext_nids = ext_nid_list;
115f579bf8eSKris Kennaway 
X509_REQ_extension_nid(int req_nid)116f579bf8eSKris Kennaway int X509_REQ_extension_nid(int req_nid)
117f579bf8eSKris Kennaway {
118f579bf8eSKris Kennaway     int i, nid;
119b077aed3SPierre Pronchery 
120f579bf8eSKris Kennaway     for (i = 0;; i++) {
121f579bf8eSKris Kennaway         nid = ext_nids[i];
1226f9291ceSJung-uk Kim         if (nid == NID_undef)
1236f9291ceSJung-uk Kim             return 0;
1246f9291ceSJung-uk Kim         else if (req_nid == nid)
1256f9291ceSJung-uk Kim             return 1;
126f579bf8eSKris Kennaway     }
127f579bf8eSKris Kennaway }
128f579bf8eSKris Kennaway 
X509_REQ_get_extension_nids(void)129f579bf8eSKris Kennaway int *X509_REQ_get_extension_nids(void)
130f579bf8eSKris Kennaway {
131f579bf8eSKris Kennaway     return ext_nids;
132f579bf8eSKris Kennaway }
133f579bf8eSKris Kennaway 
X509_REQ_set_extension_nids(int * nids)134f579bf8eSKris Kennaway void X509_REQ_set_extension_nids(int *nids)
135f579bf8eSKris Kennaway {
136f579bf8eSKris Kennaway     ext_nids = nids;
137f579bf8eSKris Kennaway }
138f579bf8eSKris Kennaway 
STACK_OF(X509_EXTENSION)139f579bf8eSKris Kennaway STACK_OF(X509_EXTENSION) *X509_REQ_get_extensions(X509_REQ *req)
140f579bf8eSKris Kennaway {
141f579bf8eSKris Kennaway     X509_ATTRIBUTE *attr;
142f579bf8eSKris Kennaway     ASN1_TYPE *ext = NULL;
1436be8ae07SJacques Vidrine     int idx, *pnid;
1443b4e3dcbSSimon L. B. Nielsen     const unsigned char *p;
1456be8ae07SJacques Vidrine 
146b077aed3SPierre Pronchery     if (req == NULL || !ext_nids)
147e71b7053SJung-uk Kim         return NULL;
1486f9291ceSJung-uk Kim     for (pnid = ext_nids; *pnid != NID_undef; pnid++) {
1496be8ae07SJacques Vidrine         idx = X509_REQ_get_attr_by_NID(req, *pnid, -1);
1506be8ae07SJacques Vidrine         if (idx == -1)
1516be8ae07SJacques Vidrine             continue;
1526be8ae07SJacques Vidrine         attr = X509_REQ_get_attr(req, idx);
153e71b7053SJung-uk Kim         ext = X509_ATTRIBUTE_get0_type(attr, 0);
154f579bf8eSKris Kennaway         break;
155f579bf8eSKris Kennaway     }
156cfc39718SJung-uk Kim     if (ext == NULL) /* no extensions is not an error */
157cfc39718SJung-uk Kim         return sk_X509_EXTENSION_new_null();
158cfc39718SJung-uk Kim     if (ext->type != V_ASN1_SEQUENCE)
1596be8ae07SJacques Vidrine         return NULL;
160f579bf8eSKris Kennaway     p = ext->value.sequence->data;
1611f13597dSJung-uk Kim     return (STACK_OF(X509_EXTENSION) *)
1621f13597dSJung-uk Kim         ASN1_item_d2i(NULL, &p, ext->value.sequence->length,
1631f13597dSJung-uk Kim                       ASN1_ITEM_rptr(X509_EXTENSIONS));
164f579bf8eSKris Kennaway }
165f579bf8eSKris Kennaway 
1666f9291ceSJung-uk Kim /*
1676f9291ceSJung-uk Kim  * Add a STACK_OF extensions to a certificate request: allow alternative OIDs
168f579bf8eSKris Kennaway  * in case we want to create a non standard one.
169f579bf8eSKris Kennaway  */
X509_REQ_add_extensions_nid(X509_REQ * req,const STACK_OF (X509_EXTENSION)* exts,int nid)170b077aed3SPierre Pronchery int X509_REQ_add_extensions_nid(X509_REQ *req,
171b077aed3SPierre Pronchery                                 const STACK_OF(X509_EXTENSION) *exts, int nid)
172f579bf8eSKris Kennaway {
173e71b7053SJung-uk Kim     int extlen;
174e71b7053SJung-uk Kim     int rv = 0;
175e71b7053SJung-uk Kim     unsigned char *ext = NULL;
176b077aed3SPierre Pronchery 
177f579bf8eSKris Kennaway     /* Generate encoding of extensions */
178b077aed3SPierre Pronchery     extlen = ASN1_item_i2d((const ASN1_VALUE *)exts, &ext,
1791f13597dSJung-uk Kim                            ASN1_ITEM_rptr(X509_EXTENSIONS));
180e71b7053SJung-uk Kim     if (extlen <= 0)
181f579bf8eSKris Kennaway         return 0;
182e71b7053SJung-uk Kim     rv = X509_REQ_add1_attr_by_NID(req, nid, V_ASN1_SEQUENCE, ext, extlen);
183e71b7053SJung-uk Kim     OPENSSL_free(ext);
184e71b7053SJung-uk Kim     return rv;
185f579bf8eSKris Kennaway }
1866f9291ceSJung-uk Kim 
187f579bf8eSKris Kennaway /* This is the normal usage: use the "official" OID */
X509_REQ_add_extensions(X509_REQ * req,const STACK_OF (X509_EXTENSION)* exts)188b077aed3SPierre Pronchery int X509_REQ_add_extensions(X509_REQ *req, const STACK_OF(X509_EXTENSION) *exts)
189f579bf8eSKris Kennaway {
190f579bf8eSKris Kennaway     return X509_REQ_add_extensions_nid(req, exts, NID_ext_req);
191f579bf8eSKris Kennaway }
192f579bf8eSKris Kennaway 
193f579bf8eSKris Kennaway /* Request attribute functions */
194f579bf8eSKris Kennaway 
X509_REQ_get_attr_count(const X509_REQ * req)195f579bf8eSKris Kennaway int X509_REQ_get_attr_count(const X509_REQ *req)
196f579bf8eSKris Kennaway {
197e71b7053SJung-uk Kim     return X509at_get_attr_count(req->req_info.attributes);
198f579bf8eSKris Kennaway }
199f579bf8eSKris Kennaway 
X509_REQ_get_attr_by_NID(const X509_REQ * req,int nid,int lastpos)2006f9291ceSJung-uk Kim int X509_REQ_get_attr_by_NID(const X509_REQ *req, int nid, int lastpos)
201f579bf8eSKris Kennaway {
202e71b7053SJung-uk Kim     return X509at_get_attr_by_NID(req->req_info.attributes, nid, lastpos);
203f579bf8eSKris Kennaway }
204f579bf8eSKris Kennaway 
X509_REQ_get_attr_by_OBJ(const X509_REQ * req,const ASN1_OBJECT * obj,int lastpos)205e71b7053SJung-uk Kim int X509_REQ_get_attr_by_OBJ(const X509_REQ *req, const ASN1_OBJECT *obj,
206f579bf8eSKris Kennaway                              int lastpos)
207f579bf8eSKris Kennaway {
208e71b7053SJung-uk Kim     return X509at_get_attr_by_OBJ(req->req_info.attributes, obj, lastpos);
209f579bf8eSKris Kennaway }
210f579bf8eSKris Kennaway 
X509_REQ_get_attr(const X509_REQ * req,int loc)211f579bf8eSKris Kennaway X509_ATTRIBUTE *X509_REQ_get_attr(const X509_REQ *req, int loc)
212f579bf8eSKris Kennaway {
213e71b7053SJung-uk Kim     return X509at_get_attr(req->req_info.attributes, loc);
214f579bf8eSKris Kennaway }
215f579bf8eSKris Kennaway 
X509_REQ_delete_attr(X509_REQ * req,int loc)216f579bf8eSKris Kennaway X509_ATTRIBUTE *X509_REQ_delete_attr(X509_REQ *req, int loc)
217f579bf8eSKris Kennaway {
218b077aed3SPierre Pronchery     X509_ATTRIBUTE *attr;
219cfc39718SJung-uk Kim 
220b077aed3SPierre Pronchery     if (req == NULL) {
221b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
222e0c4386eSCy Schubert         return NULL;
223b077aed3SPierre Pronchery     }
224b077aed3SPierre Pronchery     attr = X509at_delete_attr(req->req_info.attributes, loc);
225cfc39718SJung-uk Kim     if (attr != NULL)
226cfc39718SJung-uk Kim         req->req_info.enc.modified = 1;
227cfc39718SJung-uk Kim     return attr;
228f579bf8eSKris Kennaway }
229f579bf8eSKris Kennaway 
X509_REQ_add1_attr(X509_REQ * req,X509_ATTRIBUTE * attr)230f579bf8eSKris Kennaway int X509_REQ_add1_attr(X509_REQ *req, X509_ATTRIBUTE *attr)
231f579bf8eSKris Kennaway {
232b077aed3SPierre Pronchery     if (req == NULL) {
233b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
234b077aed3SPierre Pronchery         return 0;
235b077aed3SPierre Pronchery     }
236cfc39718SJung-uk Kim     if (!X509at_add1_attr(&req->req_info.attributes, attr))
237f579bf8eSKris Kennaway         return 0;
238cfc39718SJung-uk Kim     req->req_info.enc.modified = 1;
239cfc39718SJung-uk Kim     return 1;
240f579bf8eSKris Kennaway }
241f579bf8eSKris Kennaway 
X509_REQ_add1_attr_by_OBJ(X509_REQ * req,const ASN1_OBJECT * obj,int type,const unsigned char * bytes,int len)242f579bf8eSKris Kennaway int X509_REQ_add1_attr_by_OBJ(X509_REQ *req,
2435c87c606SMark Murray                               const ASN1_OBJECT *obj, int type,
2445c87c606SMark Murray                               const unsigned char *bytes, int len)
245f579bf8eSKris Kennaway {
246b077aed3SPierre Pronchery     if (req == NULL) {
247b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
248b077aed3SPierre Pronchery         return 0;
249b077aed3SPierre Pronchery     }
250cfc39718SJung-uk Kim     if (!X509at_add1_attr_by_OBJ(&req->req_info.attributes, obj,
2516f9291ceSJung-uk Kim                                  type, bytes, len))
252f579bf8eSKris Kennaway         return 0;
253cfc39718SJung-uk Kim     req->req_info.enc.modified = 1;
254cfc39718SJung-uk Kim     return 1;
255f579bf8eSKris Kennaway }
256f579bf8eSKris Kennaway 
X509_REQ_add1_attr_by_NID(X509_REQ * req,int nid,int type,const unsigned char * bytes,int len)257f579bf8eSKris Kennaway int X509_REQ_add1_attr_by_NID(X509_REQ *req,
258f579bf8eSKris Kennaway                               int nid, int type,
2595c87c606SMark Murray                               const unsigned char *bytes, int len)
260f579bf8eSKris Kennaway {
261b077aed3SPierre Pronchery     if (req == NULL) {
262b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
263b077aed3SPierre Pronchery         return 0;
264b077aed3SPierre Pronchery     }
265cfc39718SJung-uk Kim     if (!X509at_add1_attr_by_NID(&req->req_info.attributes, nid,
2666f9291ceSJung-uk Kim                                  type, bytes, len))
267f579bf8eSKris Kennaway         return 0;
268cfc39718SJung-uk Kim     req->req_info.enc.modified = 1;
269cfc39718SJung-uk Kim     return 1;
270f579bf8eSKris Kennaway }
271f579bf8eSKris Kennaway 
X509_REQ_add1_attr_by_txt(X509_REQ * req,const char * attrname,int type,const unsigned char * bytes,int len)272f579bf8eSKris Kennaway int X509_REQ_add1_attr_by_txt(X509_REQ *req,
2735c87c606SMark Murray                               const char *attrname, int type,
2745c87c606SMark Murray                               const unsigned char *bytes, int len)
275f579bf8eSKris Kennaway {
276b077aed3SPierre Pronchery     if (req == NULL) {
277b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
278b077aed3SPierre Pronchery         return 0;
279b077aed3SPierre Pronchery     }
280cfc39718SJung-uk Kim     if (!X509at_add1_attr_by_txt(&req->req_info.attributes, attrname,
2816f9291ceSJung-uk Kim                                  type, bytes, len))
282f579bf8eSKris Kennaway         return 0;
283cfc39718SJung-uk Kim     req->req_info.enc.modified = 1;
284cfc39718SJung-uk Kim     return 1;
285f579bf8eSKris Kennaway }
286e71b7053SJung-uk Kim 
X509_REQ_get_version(const X509_REQ * req)287e71b7053SJung-uk Kim long X509_REQ_get_version(const X509_REQ *req)
288e71b7053SJung-uk Kim {
289e71b7053SJung-uk Kim     return ASN1_INTEGER_get(req->req_info.version);
290e71b7053SJung-uk Kim }
291e71b7053SJung-uk Kim 
X509_REQ_get_subject_name(const X509_REQ * req)292e71b7053SJung-uk Kim X509_NAME *X509_REQ_get_subject_name(const X509_REQ *req)
293e71b7053SJung-uk Kim {
294e71b7053SJung-uk Kim     return req->req_info.subject;
295e71b7053SJung-uk Kim }
296e71b7053SJung-uk Kim 
X509_REQ_get0_signature(const X509_REQ * req,const ASN1_BIT_STRING ** psig,const X509_ALGOR ** palg)297e71b7053SJung-uk Kim void X509_REQ_get0_signature(const X509_REQ *req, const ASN1_BIT_STRING **psig,
298e71b7053SJung-uk Kim                              const X509_ALGOR **palg)
299e71b7053SJung-uk Kim {
300e71b7053SJung-uk Kim     if (psig != NULL)
301e71b7053SJung-uk Kim         *psig = req->signature;
302e71b7053SJung-uk Kim     if (palg != NULL)
303e71b7053SJung-uk Kim         *palg = &req->sig_alg;
304e71b7053SJung-uk Kim }
305e71b7053SJung-uk Kim 
X509_REQ_set0_signature(X509_REQ * req,ASN1_BIT_STRING * psig)30658f35182SJung-uk Kim void X509_REQ_set0_signature(X509_REQ *req, ASN1_BIT_STRING *psig)
30758f35182SJung-uk Kim {
30858f35182SJung-uk Kim     if (req->signature)
30958f35182SJung-uk Kim         ASN1_BIT_STRING_free(req->signature);
31058f35182SJung-uk Kim     req->signature = psig;
31158f35182SJung-uk Kim }
31258f35182SJung-uk Kim 
X509_REQ_set1_signature_algo(X509_REQ * req,X509_ALGOR * palg)31358f35182SJung-uk Kim int X509_REQ_set1_signature_algo(X509_REQ *req, X509_ALGOR *palg)
31458f35182SJung-uk Kim {
31558f35182SJung-uk Kim     return X509_ALGOR_copy(&req->sig_alg, palg);
31658f35182SJung-uk Kim }
31758f35182SJung-uk Kim 
X509_REQ_get_signature_nid(const X509_REQ * req)318e71b7053SJung-uk Kim int X509_REQ_get_signature_nid(const X509_REQ *req)
319e71b7053SJung-uk Kim {
320e71b7053SJung-uk Kim     return OBJ_obj2nid(req->sig_alg.algorithm);
321e71b7053SJung-uk Kim }
322e71b7053SJung-uk Kim 
i2d_re_X509_REQ_tbs(X509_REQ * req,unsigned char ** pp)323e71b7053SJung-uk Kim int i2d_re_X509_REQ_tbs(X509_REQ *req, unsigned char **pp)
324e71b7053SJung-uk Kim {
325b077aed3SPierre Pronchery     if (req == NULL) {
326b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
327b077aed3SPierre Pronchery         return 0;
328b077aed3SPierre Pronchery     }
329e71b7053SJung-uk Kim     req->req_info.enc.modified = 1;
330e71b7053SJung-uk Kim     return i2d_X509_REQ_INFO(&req->req_info, pp);
331e71b7053SJung-uk Kim }
332