17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * ==================================================================== 37c478bd9Sstevel@tonic-gate * Copyright (c) 1999 The OpenSSL Project. All rights reserved. 47c478bd9Sstevel@tonic-gate * 57c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 67c478bd9Sstevel@tonic-gate * modification, are permitted provided that the following conditions 77c478bd9Sstevel@tonic-gate * are met: 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 107c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 117c478bd9Sstevel@tonic-gate * 127c478bd9Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 137c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in 147c478bd9Sstevel@tonic-gate * the documentation and/or other materials provided with the 157c478bd9Sstevel@tonic-gate * distribution. 167c478bd9Sstevel@tonic-gate * 177c478bd9Sstevel@tonic-gate * 3. All advertising materials mentioning features or use of this 187c478bd9Sstevel@tonic-gate * software must display the following acknowledgment: 197c478bd9Sstevel@tonic-gate * "This product includes software developed by the OpenSSL Project 207c478bd9Sstevel@tonic-gate * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 217c478bd9Sstevel@tonic-gate * 227c478bd9Sstevel@tonic-gate * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 237c478bd9Sstevel@tonic-gate * endorse or promote products derived from this software without 247c478bd9Sstevel@tonic-gate * prior written permission. For written permission, please contact 257c478bd9Sstevel@tonic-gate * licensing@OpenSSL.org. 267c478bd9Sstevel@tonic-gate * 277c478bd9Sstevel@tonic-gate * 5. Products derived from this software may not be called "OpenSSL" 287c478bd9Sstevel@tonic-gate * nor may "OpenSSL" appear in their names without prior written 297c478bd9Sstevel@tonic-gate * permission of the OpenSSL Project. 307c478bd9Sstevel@tonic-gate * 317c478bd9Sstevel@tonic-gate * 6. Redistributions of any form whatsoever must retain the following 327c478bd9Sstevel@tonic-gate * acknowledgment: 337c478bd9Sstevel@tonic-gate * "This product includes software developed by the OpenSSL Project 347c478bd9Sstevel@tonic-gate * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 357c478bd9Sstevel@tonic-gate * 367c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 377c478bd9Sstevel@tonic-gate * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 387c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 397c478bd9Sstevel@tonic-gate * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 407c478bd9Sstevel@tonic-gate * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 417c478bd9Sstevel@tonic-gate * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 427c478bd9Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 437c478bd9Sstevel@tonic-gate * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 447c478bd9Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 457c478bd9Sstevel@tonic-gate * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 467c478bd9Sstevel@tonic-gate * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 477c478bd9Sstevel@tonic-gate * OF THE POSSIBILITY OF SUCH DAMAGE. 487c478bd9Sstevel@tonic-gate * ==================================================================== 497c478bd9Sstevel@tonic-gate * 507c478bd9Sstevel@tonic-gate * This product includes cryptographic software written by Eric Young 517c478bd9Sstevel@tonic-gate * (eay@cryptsoft.com). This product includes software written by Tim 527c478bd9Sstevel@tonic-gate * Hudson (tjh@cryptsoft.com). 537c478bd9Sstevel@tonic-gate * 547c478bd9Sstevel@tonic-gate */ 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate /* 577c478bd9Sstevel@tonic-gate * Copyright 2002, 2003 Sun Microsystems, Inc. All rights reserved. 587c478bd9Sstevel@tonic-gate * Use is subject to license terms. 597c478bd9Sstevel@tonic-gate * 607c478bd9Sstevel@tonic-gate * All of the functions included here are internal to the pkcs12 functions 617c478bd9Sstevel@tonic-gate * in this library. None of these are exposed. 627c478bd9Sstevel@tonic-gate */ 637c478bd9Sstevel@tonic-gate 64*70f9559bSTheo Schlossnagle /* 65*70f9559bSTheo Schlossnagle * Copyright (c) 2012, OmniTI Computer Consulting, Inc. All rights reserved. 66*70f9559bSTheo Schlossnagle */ 67*70f9559bSTheo Schlossnagle 687c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate #include <stdio.h> 717c478bd9Sstevel@tonic-gate #include <string.h> 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate #include <openssl/crypto.h> 747c478bd9Sstevel@tonic-gate #include <openssl/err.h> 757c478bd9Sstevel@tonic-gate #include <openssl/x509.h> 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate #include <openssl/pkcs12.h> 787c478bd9Sstevel@tonic-gate #include <p12aux.h> 797c478bd9Sstevel@tonic-gate #include <auxutil.h> 807c478bd9Sstevel@tonic-gate #include <p12err.h> 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate /* 837c478bd9Sstevel@tonic-gate * asc2bmpstring - Convert a regular C ASCII string to an ASn1_STRING in 847c478bd9Sstevel@tonic-gate * ASN1_BMPSTRING format. 857c478bd9Sstevel@tonic-gate * 867c478bd9Sstevel@tonic-gate * Arguments: 877c478bd9Sstevel@tonic-gate * str - String to be convered. 887c478bd9Sstevel@tonic-gate * len - Length of the string. 897c478bd9Sstevel@tonic-gate * 907c478bd9Sstevel@tonic-gate * Returns: 917c478bd9Sstevel@tonic-gate * == NULL - An error occurred. Error information (accessible by 927c478bd9Sstevel@tonic-gate * ERR_get_error()) is set. 937c478bd9Sstevel@tonic-gate * != NULL - Points to an ASN1_BMPSTRING structure with the converted 947c478bd9Sstevel@tonic-gate * string as a value. 957c478bd9Sstevel@tonic-gate */ 967c478bd9Sstevel@tonic-gate ASN1_BMPSTRING * 977c478bd9Sstevel@tonic-gate asc2bmpstring(const char *str, int len) 987c478bd9Sstevel@tonic-gate { 997c478bd9Sstevel@tonic-gate ASN1_BMPSTRING *bmp = NULL; 1007c478bd9Sstevel@tonic-gate uchar_t *uni = NULL; 1017c478bd9Sstevel@tonic-gate int unilen; 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate /* Convert the character to the bmp format. */ 104*70f9559bSTheo Schlossnagle #if OPENSSL_VERSION_NUMBER < 0x10000000L 1057c478bd9Sstevel@tonic-gate if (asc2uni(str, len, &uni, &unilen) == 0) { 106*70f9559bSTheo Schlossnagle #else 107*70f9559bSTheo Schlossnagle if (OPENSSL_asc2uni(str, len, &uni, &unilen) == 0) { 108*70f9559bSTheo Schlossnagle #endif 1097c478bd9Sstevel@tonic-gate SUNWerr(SUNW_F_ASC2BMPSTRING, SUNW_R_MEMORY_FAILURE); 1107c478bd9Sstevel@tonic-gate return (NULL); 1117c478bd9Sstevel@tonic-gate } 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate /* 1147c478bd9Sstevel@tonic-gate * Adjust for possible pair of NULL bytes at the end because 1157c478bd9Sstevel@tonic-gate * asc2uni() returns a doubly null terminated string. 1167c478bd9Sstevel@tonic-gate */ 1177c478bd9Sstevel@tonic-gate if (uni[unilen - 1] == '\0' && uni[unilen - 2] == '\0') 1187c478bd9Sstevel@tonic-gate unilen -= 2; 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate /* Construct comparison string with correct format */ 1217c478bd9Sstevel@tonic-gate bmp = M_ASN1_BMPSTRING_new(); 1227c478bd9Sstevel@tonic-gate if (bmp == NULL) { 1237c478bd9Sstevel@tonic-gate SUNWerr(SUNW_F_ASC2BMPSTRING, SUNW_R_MEMORY_FAILURE); 1247c478bd9Sstevel@tonic-gate OPENSSL_free(uni); 1257c478bd9Sstevel@tonic-gate return (NULL); 1267c478bd9Sstevel@tonic-gate } 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate bmp->data = uni; 1297c478bd9Sstevel@tonic-gate bmp->length = unilen; 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate return (bmp); 1327c478bd9Sstevel@tonic-gate } 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate /* 1357c478bd9Sstevel@tonic-gate * utf82ascstr - Convert a UTF8STRING string to a regular C ASCII string. 1367c478bd9Sstevel@tonic-gate * This goes through an intermediate step with a ASN1_STRING type of 1377c478bd9Sstevel@tonic-gate * IA5STRING (International Alphabet 5, which is the same as ASCII). 1387c478bd9Sstevel@tonic-gate * 1397c478bd9Sstevel@tonic-gate * Arguments: 1407c478bd9Sstevel@tonic-gate * str - UTF8STRING to be converted. 1417c478bd9Sstevel@tonic-gate * 1427c478bd9Sstevel@tonic-gate * Returns: 1437c478bd9Sstevel@tonic-gate * == NULL - An error occurred. Error information (accessible by 1447c478bd9Sstevel@tonic-gate * ERR_get_error()) is set. 1457c478bd9Sstevel@tonic-gate * != NULL - Points to a NULL-termianted ASCII string. The caller must 1467c478bd9Sstevel@tonic-gate * free it. 1477c478bd9Sstevel@tonic-gate */ 1487c478bd9Sstevel@tonic-gate uchar_t * 1497c478bd9Sstevel@tonic-gate utf82ascstr(ASN1_UTF8STRING *ustr) 1507c478bd9Sstevel@tonic-gate { 1517c478bd9Sstevel@tonic-gate ASN1_STRING tmpstr; 1527c478bd9Sstevel@tonic-gate ASN1_STRING *astr = &tmpstr; 1537c478bd9Sstevel@tonic-gate uchar_t *retstr = NULL; 1547c478bd9Sstevel@tonic-gate int mbflag; 1557c478bd9Sstevel@tonic-gate int ret; 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate if (ustr == NULL || ustr->type != V_ASN1_UTF8STRING) { 1587c478bd9Sstevel@tonic-gate SUNWerr(SUNW_F_UTF82ASCSTR, SUNW_R_INVALID_ARG); 1597c478bd9Sstevel@tonic-gate return (NULL); 1607c478bd9Sstevel@tonic-gate } 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate mbflag = MBSTRING_ASC; 1637c478bd9Sstevel@tonic-gate tmpstr.data = NULL; 1647c478bd9Sstevel@tonic-gate tmpstr.length = 0; 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate ret = ASN1_mbstring_copy(&astr, ustr->data, ustr->length, mbflag, 1677c478bd9Sstevel@tonic-gate B_ASN1_IA5STRING); 1687c478bd9Sstevel@tonic-gate if (ret < 0) { 1697c478bd9Sstevel@tonic-gate SUNWerr(SUNW_F_UTF82ASCSTR, SUNW_R_STR_CONVERT_ERR); 1707c478bd9Sstevel@tonic-gate return (NULL); 1717c478bd9Sstevel@tonic-gate } 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate retstr = OPENSSL_malloc(astr->length + 1); 1747c478bd9Sstevel@tonic-gate if (retstr == NULL) { 1757c478bd9Sstevel@tonic-gate SUNWerr(SUNW_F_UTF82ASCSTR, SUNW_R_MEMORY_FAILURE); 1767c478bd9Sstevel@tonic-gate return (NULL); 1777c478bd9Sstevel@tonic-gate } 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate (void) memcpy(retstr, astr->data, astr->length); 1807c478bd9Sstevel@tonic-gate retstr[astr->length] = '\0'; 1817c478bd9Sstevel@tonic-gate OPENSSL_free(astr->data); 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate return (retstr); 1847c478bd9Sstevel@tonic-gate } 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate /* 1877c478bd9Sstevel@tonic-gate * set_results - Given two pointers to stacks of private keys, certs or CA 1887c478bd9Sstevel@tonic-gate * CA certs, either copy the second stack to the first, or append the 1897c478bd9Sstevel@tonic-gate * contents of the second to the first. 1907c478bd9Sstevel@tonic-gate * 1917c478bd9Sstevel@tonic-gate * Arguments: 1927c478bd9Sstevel@tonic-gate * pkeys - Points to stack of pkeys 1937c478bd9Sstevel@tonic-gate * work_kl - Points to working stack of pkeys 1947c478bd9Sstevel@tonic-gate * certs - Points to stack of certs 1957c478bd9Sstevel@tonic-gate * work_cl - Points to working stack of certs 1967c478bd9Sstevel@tonic-gate * cacerts - Points to stack of CA certs 1977c478bd9Sstevel@tonic-gate * work_ca - Points to working stack of CA certs 1987c478bd9Sstevel@tonic-gate * xtrakeys - Points to stack of unmatcned pkeys 1997c478bd9Sstevel@tonic-gate * work_xl - Points to working stack of unmatcned pkeys 2007c478bd9Sstevel@tonic-gate * 2017c478bd9Sstevel@tonic-gate * The arguments are in pairs. The first of each pair points to a stack 2027c478bd9Sstevel@tonic-gate * of keys or certs. The second of the pair points at a 'working stack' 2037c478bd9Sstevel@tonic-gate * of the same type of entities. Actions taken are as follows: 2047c478bd9Sstevel@tonic-gate * 2057c478bd9Sstevel@tonic-gate * - If either the first or second argument is NULL, or if there are no 2067c478bd9Sstevel@tonic-gate * members in the second stack, there is nothing to do. 2077c478bd9Sstevel@tonic-gate * - If the first argument points to a pointer which is NULL, then there 2087c478bd9Sstevel@tonic-gate * is no existing stack for the first argument. Copy the stack pointer 2097c478bd9Sstevel@tonic-gate * from the second argument to the first argument and NULL out the stack 2107c478bd9Sstevel@tonic-gate * pointer for the second. 2117c478bd9Sstevel@tonic-gate * - Otherwise, go through the elements of the second stack, removing each 2127c478bd9Sstevel@tonic-gate * and adding it to the first stack. 2137c478bd9Sstevel@tonic-gate * 2147c478bd9Sstevel@tonic-gate * Returns: 2157c478bd9Sstevel@tonic-gate * == -1 - An error occurred. Call ERR_get_error() to get error information. 2167c478bd9Sstevel@tonic-gate * == 0 - No matching returns were found. 2177c478bd9Sstevel@tonic-gate * > 0 - This is the arithmetic 'or' of the FOUND_* bits that indicate which 2187c478bd9Sstevel@tonic-gate * of the requested entries were manipulated. 2197c478bd9Sstevel@tonic-gate */ 2207c478bd9Sstevel@tonic-gate int 2217c478bd9Sstevel@tonic-gate set_results(STACK_OF(EVP_PKEY) **pkeys, STACK_OF(EVP_PKEY) **work_kl, 2227c478bd9Sstevel@tonic-gate STACK_OF(X509) **certs, STACK_OF(X509) **work_cl, 2237c478bd9Sstevel@tonic-gate STACK_OF(X509) **cacerts, STACK_OF(X509) **work_ca, 2247c478bd9Sstevel@tonic-gate STACK_OF(EVP_PKEY) **xtrakeys, STACK_OF(EVP_PKEY) **work_xl) 2257c478bd9Sstevel@tonic-gate { 2267c478bd9Sstevel@tonic-gate int retval = 0; 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate if (pkeys != NULL && work_kl != NULL && *work_kl != NULL && 2297c478bd9Sstevel@tonic-gate sk_EVP_PKEY_num(*work_kl) > 0) { 2307c478bd9Sstevel@tonic-gate if (*pkeys == NULL) { 2317c478bd9Sstevel@tonic-gate *pkeys = *work_kl; 2327c478bd9Sstevel@tonic-gate *work_kl = NULL; 2337c478bd9Sstevel@tonic-gate } else { 2347c478bd9Sstevel@tonic-gate if (sunw_append_keys(*pkeys, *work_kl) < 0) { 2357c478bd9Sstevel@tonic-gate return (-1); 2367c478bd9Sstevel@tonic-gate } 2377c478bd9Sstevel@tonic-gate } 2387c478bd9Sstevel@tonic-gate retval |= FOUND_PKEY; 2397c478bd9Sstevel@tonic-gate } 2407c478bd9Sstevel@tonic-gate if (certs != NULL && work_cl != NULL && *work_cl != NULL && 2417c478bd9Sstevel@tonic-gate sk_X509_num(*work_cl) > 0) { 2427c478bd9Sstevel@tonic-gate if (*certs == NULL) { 2437c478bd9Sstevel@tonic-gate *certs = *work_cl; 2447c478bd9Sstevel@tonic-gate *work_cl = NULL; 2457c478bd9Sstevel@tonic-gate } else { 2467c478bd9Sstevel@tonic-gate if (move_certs(*certs, *work_cl) < 0) { 2477c478bd9Sstevel@tonic-gate return (-1); 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate } 2507c478bd9Sstevel@tonic-gate retval |= FOUND_CERT; 2517c478bd9Sstevel@tonic-gate } 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate if (cacerts != NULL && work_ca != NULL && *work_ca != NULL && 2547c478bd9Sstevel@tonic-gate sk_X509_num(*work_ca) > 0) { 2557c478bd9Sstevel@tonic-gate if (*cacerts == NULL) { 2567c478bd9Sstevel@tonic-gate *cacerts = *work_ca; 2577c478bd9Sstevel@tonic-gate *work_ca = NULL; 2587c478bd9Sstevel@tonic-gate } else { 2597c478bd9Sstevel@tonic-gate if (move_certs(*cacerts, *work_ca) < 0) { 2607c478bd9Sstevel@tonic-gate return (-1); 2617c478bd9Sstevel@tonic-gate } 2627c478bd9Sstevel@tonic-gate } 2637c478bd9Sstevel@tonic-gate retval |= FOUND_CA_CERTS; 2647c478bd9Sstevel@tonic-gate } 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate if (xtrakeys != NULL && work_xl != NULL && *work_xl != NULL && 2677c478bd9Sstevel@tonic-gate sk_EVP_PKEY_num(*work_xl) > 0) { 2687c478bd9Sstevel@tonic-gate if (*xtrakeys == NULL) { 2697c478bd9Sstevel@tonic-gate *xtrakeys = *work_xl; 2707c478bd9Sstevel@tonic-gate *work_xl = NULL; 2717c478bd9Sstevel@tonic-gate } else { 2727c478bd9Sstevel@tonic-gate if (sunw_append_keys(*xtrakeys, *work_xl) < 0) { 2737c478bd9Sstevel@tonic-gate return (-1); 2747c478bd9Sstevel@tonic-gate } 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate retval |= FOUND_XPKEY; 2777c478bd9Sstevel@tonic-gate } 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate return (retval); 2807c478bd9Sstevel@tonic-gate } 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate /* 2837c478bd9Sstevel@tonic-gate * find_attr - Look for a given attribute of the type associated with the NID. 2847c478bd9Sstevel@tonic-gate * 2857c478bd9Sstevel@tonic-gate * Arguments: 2867c478bd9Sstevel@tonic-gate * nid - NID for the attribute to be found (either NID_friendlyName or 2877c478bd9Sstevel@tonic-gate * NID_locakKeyId) 2887c478bd9Sstevel@tonic-gate * str - ASN1_STRING-type structure containing the value to be found, 2897c478bd9Sstevel@tonic-gate * FriendlyName expects a ASN1_BMPSTRING and localKeyID uses a 2907c478bd9Sstevel@tonic-gate * ASN1_STRING. 2917c478bd9Sstevel@tonic-gate * kl - Points to a stack of private keys. 2927c478bd9Sstevel@tonic-gate * pkey - Points at a location where the address of the matching private 2937c478bd9Sstevel@tonic-gate * key will be stored. 2947c478bd9Sstevel@tonic-gate * cl - Points to a stack of client certs with matching private keys. 2957c478bd9Sstevel@tonic-gate * cert - Points to locaiton where the address of the matching client cert 2967c478bd9Sstevel@tonic-gate * will be returned 2977c478bd9Sstevel@tonic-gate * 2987c478bd9Sstevel@tonic-gate * This function is designed to process lists of certs and private keys. 2997c478bd9Sstevel@tonic-gate * This is made complex because these the attributes are stored differently 3007c478bd9Sstevel@tonic-gate * for certs and for keys. For certs, only a few attributes are retained. 3017c478bd9Sstevel@tonic-gate * FriendlyName is stored in the aux structure, under the name 'alias'. 3027c478bd9Sstevel@tonic-gate * LocalKeyId is also stored in the aux structure, under the name 'keyid'. 3037c478bd9Sstevel@tonic-gate * A pkey structure has a stack of attributes. 3047c478bd9Sstevel@tonic-gate * 3057c478bd9Sstevel@tonic-gate * The basic approach is: 3067c478bd9Sstevel@tonic-gate * - If there there is no stack of certs but a stack of private keys exists, 3077c478bd9Sstevel@tonic-gate * search the stack of keys for a match. Alternately, if there is a stack 3087c478bd9Sstevel@tonic-gate * of certs and no private keys, search the certs. 3097c478bd9Sstevel@tonic-gate * 3107c478bd9Sstevel@tonic-gate * - If there are both certs and keys, assume that the matching certs and 3117c478bd9Sstevel@tonic-gate * keys are in their respective stacks, with matching entries in the same 3127c478bd9Sstevel@tonic-gate * order. Search for the name or keyid in the stack of certs. If it is 3137c478bd9Sstevel@tonic-gate * not found, then this function returns 0 (nothing found). 3147c478bd9Sstevel@tonic-gate * 3157c478bd9Sstevel@tonic-gate * - Once a cert is found, verify that the key actually matches by 3167c478bd9Sstevel@tonic-gate * comparing the private key with the public key (in the cert). 3177c478bd9Sstevel@tonic-gate * If they don't match, return an error. 3187c478bd9Sstevel@tonic-gate * 3197c478bd9Sstevel@tonic-gate * A pointer to cert and/or pkey which matches the name or keyid is stored 3207c478bd9Sstevel@tonic-gate * in the return arguments. 3217c478bd9Sstevel@tonic-gate * 3227c478bd9Sstevel@tonic-gate * Returns: 3237c478bd9Sstevel@tonic-gate * 0 - No matches were found. 3247c478bd9Sstevel@tonic-gate * > 0 - Bits set based on FOUND_* definitions, indicating what was found. 3257c478bd9Sstevel@tonic-gate * This can be FOUND_PKEY, FOUND_CERT or (FOUND_PKEY | FOUND_CERT). 3267c478bd9Sstevel@tonic-gate */ 3277c478bd9Sstevel@tonic-gate int 3287c478bd9Sstevel@tonic-gate find_attr(int nid, ASN1_STRING *str, STACK_OF(EVP_PKEY) *kl, EVP_PKEY **pkey, 3297c478bd9Sstevel@tonic-gate STACK_OF(X509) *cl, X509 **cert) 3307c478bd9Sstevel@tonic-gate { 3317c478bd9Sstevel@tonic-gate ASN1_UTF8STRING *ustr = NULL; 3327c478bd9Sstevel@tonic-gate ASN1_STRING *s; 3337c478bd9Sstevel@tonic-gate ASN1_TYPE *t; 3347c478bd9Sstevel@tonic-gate EVP_PKEY *p; 3357c478bd9Sstevel@tonic-gate uchar_t *fname = NULL; 3367c478bd9Sstevel@tonic-gate X509 *x; 3377c478bd9Sstevel@tonic-gate int found = 0; 3387c478bd9Sstevel@tonic-gate int chkcerts; 3397c478bd9Sstevel@tonic-gate int len; 3407c478bd9Sstevel@tonic-gate int res; 3417c478bd9Sstevel@tonic-gate int c = -1; 3427c478bd9Sstevel@tonic-gate int k = -1; 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate chkcerts = (cert != NULL || pkey != NULL) && cl != NULL; 3457c478bd9Sstevel@tonic-gate if (chkcerts && nid == NID_friendlyName && 3467c478bd9Sstevel@tonic-gate str->type == V_ASN1_BMPSTRING) { 3477c478bd9Sstevel@tonic-gate ustr = ASN1_UTF8STRING_new(); 3487c478bd9Sstevel@tonic-gate if (ustr == NULL) { 3497c478bd9Sstevel@tonic-gate SUNWerr(SUNW_F_FINDATTR, SUNW_R_MEMORY_FAILURE); 3507c478bd9Sstevel@tonic-gate return (0); 3517c478bd9Sstevel@tonic-gate } 3527c478bd9Sstevel@tonic-gate len = ASN1_STRING_to_UTF8(&fname, str); 3537c478bd9Sstevel@tonic-gate if (fname == NULL) { 3547c478bd9Sstevel@tonic-gate ASN1_UTF8STRING_free(ustr); 3557c478bd9Sstevel@tonic-gate SUNWerr(SUNW_F_FINDATTR, SUNW_R_STR_CONVERT_ERR); 3567c478bd9Sstevel@tonic-gate return (0); 3577c478bd9Sstevel@tonic-gate } 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate if (ASN1_STRING_set(ustr, fname, len) == 0) { 3607c478bd9Sstevel@tonic-gate ASN1_UTF8STRING_free(ustr); 3617c478bd9Sstevel@tonic-gate OPENSSL_free(fname); 3627c478bd9Sstevel@tonic-gate SUNWerr(SUNW_F_FINDATTR, SUNW_R_MEMORY_FAILURE); 3637c478bd9Sstevel@tonic-gate return (0); 3647c478bd9Sstevel@tonic-gate } 3657c478bd9Sstevel@tonic-gate } 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate if (chkcerts) { 3687c478bd9Sstevel@tonic-gate for (c = 0; c < sk_X509_num(cl); c++) { 3697c478bd9Sstevel@tonic-gate res = -1; 3707c478bd9Sstevel@tonic-gate x = sk_X509_value(cl, c); 3717c478bd9Sstevel@tonic-gate if (nid == NID_friendlyName && ustr != NULL) { 3727c478bd9Sstevel@tonic-gate if (x->aux == NULL || x->aux->alias == NULL) 3737c478bd9Sstevel@tonic-gate continue; 3747c478bd9Sstevel@tonic-gate s = x->aux->alias; 3757c478bd9Sstevel@tonic-gate if (s != NULL && s->type == ustr->type && 3767c478bd9Sstevel@tonic-gate s->data != NULL) { 3777c478bd9Sstevel@tonic-gate res = ASN1_STRING_cmp(s, ustr); 3787c478bd9Sstevel@tonic-gate } 3797c478bd9Sstevel@tonic-gate } else { 3807c478bd9Sstevel@tonic-gate if (x->aux == NULL || x->aux->keyid == NULL) 3817c478bd9Sstevel@tonic-gate continue; 3827c478bd9Sstevel@tonic-gate s = x->aux->keyid; 3837c478bd9Sstevel@tonic-gate if (s != NULL && s->type == str->type && 3847c478bd9Sstevel@tonic-gate s->data != NULL) { 3857c478bd9Sstevel@tonic-gate res = ASN1_STRING_cmp(s, str); 3867c478bd9Sstevel@tonic-gate } 3877c478bd9Sstevel@tonic-gate } 3887c478bd9Sstevel@tonic-gate if (res == 0) { 3897c478bd9Sstevel@tonic-gate if (cert != NULL) 3907c478bd9Sstevel@tonic-gate *cert = sk_X509_delete(cl, c); 3917c478bd9Sstevel@tonic-gate found = FOUND_CERT; 3927c478bd9Sstevel@tonic-gate break; 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate if (ustr != NULL) { 3967c478bd9Sstevel@tonic-gate ASN1_UTF8STRING_free(ustr); 3977c478bd9Sstevel@tonic-gate OPENSSL_free(fname); 3987c478bd9Sstevel@tonic-gate } 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate if (pkey != NULL && kl != NULL) { 4027c478bd9Sstevel@tonic-gate /* 4037c478bd9Sstevel@tonic-gate * Looking for pkey to match a cert? If so, assume that 4047c478bd9Sstevel@tonic-gate * lists of certs and their matching pkeys are in the same 4057c478bd9Sstevel@tonic-gate * order. Call X509_check_private_key() to verify this 4067c478bd9Sstevel@tonic-gate * assumption. 4077c478bd9Sstevel@tonic-gate */ 4087c478bd9Sstevel@tonic-gate if (found != 0 && cert != NULL) { 4097c478bd9Sstevel@tonic-gate k = c; 4107c478bd9Sstevel@tonic-gate p = sk_EVP_PKEY_value(kl, k); 4117c478bd9Sstevel@tonic-gate if (X509_check_private_key(x, p) != 0) { 4127c478bd9Sstevel@tonic-gate if (pkey != NULL) 4137c478bd9Sstevel@tonic-gate *pkey = sk_EVP_PKEY_delete(kl, k); 4147c478bd9Sstevel@tonic-gate found |= FOUND_PKEY; 4157c478bd9Sstevel@tonic-gate } 4167c478bd9Sstevel@tonic-gate } else if (cert == NULL) { 4177c478bd9Sstevel@tonic-gate for (k = 0; k < sk_EVP_PKEY_num(kl); k++) { 4187c478bd9Sstevel@tonic-gate p = sk_EVP_PKEY_value(kl, k); 4197c478bd9Sstevel@tonic-gate if (p == NULL || p->attributes == NULL) 4207c478bd9Sstevel@tonic-gate continue; 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate t = PKCS12_get_attr_gen(p->attributes, nid); 4237c478bd9Sstevel@tonic-gate if (t != NULL || ASN1_STRING_cmp(str, 4247c478bd9Sstevel@tonic-gate t->value.asn1_string) == 0) 4257c478bd9Sstevel@tonic-gate continue; 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate found |= FOUND_PKEY; 4287c478bd9Sstevel@tonic-gate if (pkey != NULL) 4297c478bd9Sstevel@tonic-gate *pkey = sk_EVP_PKEY_delete(kl, k); 4307c478bd9Sstevel@tonic-gate break; 4317c478bd9Sstevel@tonic-gate } 4327c478bd9Sstevel@tonic-gate } 4337c478bd9Sstevel@tonic-gate } 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate return (found); 4367c478bd9Sstevel@tonic-gate } 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate /* 4397c478bd9Sstevel@tonic-gate * find_attr_by_nid - Given a ASN1_TYPE, return the offset of a X509_ATTRIBUTE 4407c478bd9Sstevel@tonic-gate * of the type specified by the given NID. 4417c478bd9Sstevel@tonic-gate * 4427c478bd9Sstevel@tonic-gate * Arguments: 4437c478bd9Sstevel@tonic-gate * attrs - Stack of attributes to search 4447c478bd9Sstevel@tonic-gate * nid - NID of the attribute being searched for 4457c478bd9Sstevel@tonic-gate * 4467c478bd9Sstevel@tonic-gate * Returns: 4477c478bd9Sstevel@tonic-gate * -1 None found 4487c478bd9Sstevel@tonic-gate * != -1 Offset of the matching attribute. 4497c478bd9Sstevel@tonic-gate */ 4507c478bd9Sstevel@tonic-gate int 4517c478bd9Sstevel@tonic-gate find_attr_by_nid(STACK_OF(X509_ATTRIBUTE) *attrs, int nid) 4527c478bd9Sstevel@tonic-gate { 4537c478bd9Sstevel@tonic-gate X509_ATTRIBUTE *a; 4547c478bd9Sstevel@tonic-gate int i; 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate if (attrs == NULL) 4577c478bd9Sstevel@tonic-gate return (-1); 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate for (i = 0; i < sk_X509_ATTRIBUTE_num(attrs); i++) { 4607c478bd9Sstevel@tonic-gate a = sk_X509_ATTRIBUTE_value(attrs, i); 4617c478bd9Sstevel@tonic-gate if (OBJ_obj2nid(a->object) == nid) 4627c478bd9Sstevel@tonic-gate return (i); 4637c478bd9Sstevel@tonic-gate } 4647c478bd9Sstevel@tonic-gate return (-1); 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate /* 4687c478bd9Sstevel@tonic-gate * get_key_cert - Get a cert and its matching key from the stacks of certs 4697c478bd9Sstevel@tonic-gate * and keys. They are removed from the stacks. 4707c478bd9Sstevel@tonic-gate * 4717c478bd9Sstevel@tonic-gate * Arguments: 4727c478bd9Sstevel@tonic-gate * n - Offset of the entries to return. 4737c478bd9Sstevel@tonic-gate * kl - Points to a stack of private keys that matches the list of 4747c478bd9Sstevel@tonic-gate * certs below. 4757c478bd9Sstevel@tonic-gate * pkey - Points at location where the address of the matching private 4767c478bd9Sstevel@tonic-gate * key will be stored. 4777c478bd9Sstevel@tonic-gate * cl - Points to a stack of client certs with matching private keys. 4787c478bd9Sstevel@tonic-gate * cert - Points to locaiton where the address of the matching client cert 4797c478bd9Sstevel@tonic-gate * will be returned 4807c478bd9Sstevel@tonic-gate * 4817c478bd9Sstevel@tonic-gate * The assumption is that the stacks of keys and certs contain key/cert pairs, 4827c478bd9Sstevel@tonic-gate * with entries in the same order and hence at the same offset. Provided 4837c478bd9Sstevel@tonic-gate * the key and cert selected match, each will be removed from its stack and 4847c478bd9Sstevel@tonic-gate * returned. 4857c478bd9Sstevel@tonic-gate * 4867c478bd9Sstevel@tonic-gate * A stack of certs can be passed in without a stack of private keys, and vise 4877c478bd9Sstevel@tonic-gate * versa. In that case, the indicated key/cert will be returned. 4887c478bd9Sstevel@tonic-gate * 4897c478bd9Sstevel@tonic-gate * Returns: 4907c478bd9Sstevel@tonic-gate * 0 - No matches were found. 4917c478bd9Sstevel@tonic-gate * > 0 - Bits set based on FOUND_* definitions, indicating what is returned. 4927c478bd9Sstevel@tonic-gate * This can be FOUND_PKEY, FOUND_CERT or (FOUND_PKEY | FOUND_CERT). 4937c478bd9Sstevel@tonic-gate */ 4947c478bd9Sstevel@tonic-gate int 4957c478bd9Sstevel@tonic-gate get_key_cert(int n, STACK_OF(EVP_PKEY) *kl, EVP_PKEY **pkey, STACK_OF(X509) *cl, 4967c478bd9Sstevel@tonic-gate X509 **cert) 4977c478bd9Sstevel@tonic-gate { 4987c478bd9Sstevel@tonic-gate int retval = 0; 4997c478bd9Sstevel@tonic-gate int nk; 5007c478bd9Sstevel@tonic-gate int nc; 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate nk = (kl != NULL) ? sk_EVP_PKEY_num(kl) : 0; 5037c478bd9Sstevel@tonic-gate nc = (cl != NULL) ? sk_X509_num(cl) : 0; 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate if (pkey != NULL && *pkey == NULL) { 5067c478bd9Sstevel@tonic-gate if (nk > 0 && n >= 0 || n < nk) { 5077c478bd9Sstevel@tonic-gate *pkey = sk_EVP_PKEY_delete(kl, n); 5087c478bd9Sstevel@tonic-gate if (*pkey != NULL) 5097c478bd9Sstevel@tonic-gate retval |= FOUND_PKEY; 5107c478bd9Sstevel@tonic-gate } 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate if (cert != NULL && *cert == NULL) { 5147c478bd9Sstevel@tonic-gate if (nc > 0 && n >= 0 && n < nc) { 5157c478bd9Sstevel@tonic-gate *cert = sk_X509_delete(cl, n); 5167c478bd9Sstevel@tonic-gate if (*cert != NULL) 5177c478bd9Sstevel@tonic-gate retval |= FOUND_CERT; 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate } 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate return (retval); 5227c478bd9Sstevel@tonic-gate } 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate /* 5257c478bd9Sstevel@tonic-gate * type2attrib - Given a ASN1_TYPE, return a X509_ATTRIBUTE of the type 5267c478bd9Sstevel@tonic-gate * specified by the given NID. 5277c478bd9Sstevel@tonic-gate * 5287c478bd9Sstevel@tonic-gate * Arguments: 5297c478bd9Sstevel@tonic-gate * ty - Type structure to be made into an attribute 5307c478bd9Sstevel@tonic-gate * nid - NID of the attribute 5317c478bd9Sstevel@tonic-gate * 5327c478bd9Sstevel@tonic-gate * Returns: 5337c478bd9Sstevel@tonic-gate * NULL An error occurred. 5347c478bd9Sstevel@tonic-gate * != NULL An X509_ATTRIBUTE structure. 5357c478bd9Sstevel@tonic-gate */ 5367c478bd9Sstevel@tonic-gate X509_ATTRIBUTE * 5377c478bd9Sstevel@tonic-gate type2attrib(ASN1_TYPE *ty, int nid) 5387c478bd9Sstevel@tonic-gate { 5397c478bd9Sstevel@tonic-gate X509_ATTRIBUTE *a; 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate if ((a = X509_ATTRIBUTE_new()) == NULL || 5427c478bd9Sstevel@tonic-gate (a->value.set = sk_ASN1_TYPE_new_null()) == NULL || 5437c478bd9Sstevel@tonic-gate sk_ASN1_TYPE_push(a->value.set, ty) == 0) { 5447c478bd9Sstevel@tonic-gate if (a != NULL) 5457c478bd9Sstevel@tonic-gate X509_ATTRIBUTE_free(a); 5467c478bd9Sstevel@tonic-gate SUNWerr(SUNW_F_TYPE2ATTRIB, SUNW_R_MEMORY_FAILURE); 5477c478bd9Sstevel@tonic-gate return (NULL); 5487c478bd9Sstevel@tonic-gate } 5497c478bd9Sstevel@tonic-gate a->single = 0; 5507c478bd9Sstevel@tonic-gate a->object = OBJ_nid2obj(nid); 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate return (a); 5537c478bd9Sstevel@tonic-gate } 5547c478bd9Sstevel@tonic-gate 5557c478bd9Sstevel@tonic-gate /* 5567c478bd9Sstevel@tonic-gate * attrib2type - Given a X509_ATTRIBUTE, return pointer to the ASN1_TYPE 5577c478bd9Sstevel@tonic-gate * component 5587c478bd9Sstevel@tonic-gate * 5597c478bd9Sstevel@tonic-gate * Arguments: 5607c478bd9Sstevel@tonic-gate * attr - Attribute structure containing a type. 5617c478bd9Sstevel@tonic-gate * 5627c478bd9Sstevel@tonic-gate * Returns: 5637c478bd9Sstevel@tonic-gate * NULL An error occurred. 5647c478bd9Sstevel@tonic-gate * != NULL An ASN1_TYPE structure. 5657c478bd9Sstevel@tonic-gate */ 5667c478bd9Sstevel@tonic-gate ASN1_TYPE * 5677c478bd9Sstevel@tonic-gate attrib2type(X509_ATTRIBUTE *attr) 5687c478bd9Sstevel@tonic-gate { 5697c478bd9Sstevel@tonic-gate ASN1_TYPE *ty = NULL; 5707c478bd9Sstevel@tonic-gate 5717c478bd9Sstevel@tonic-gate if (attr == NULL || attr->single == 1) 5727c478bd9Sstevel@tonic-gate return (NULL); 5737c478bd9Sstevel@tonic-gate 5747c478bd9Sstevel@tonic-gate if (sk_ASN1_TYPE_num(attr->value.set) > 0) 5757c478bd9Sstevel@tonic-gate ty = sk_ASN1_TYPE_value(attr->value.set, 0); 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate return (ty); 5787c478bd9Sstevel@tonic-gate } 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate /* 5817c478bd9Sstevel@tonic-gate * move_certs - Given two stacks of certs, remove the certs from 5827c478bd9Sstevel@tonic-gate * the second stack and append them to the first. 5837c478bd9Sstevel@tonic-gate * 5847c478bd9Sstevel@tonic-gate * Arguments: 5857c478bd9Sstevel@tonic-gate * dst - the stack to receive the certs from 'src' 5867c478bd9Sstevel@tonic-gate * src - the stack whose certs are to be moved. 5877c478bd9Sstevel@tonic-gate * 5887c478bd9Sstevel@tonic-gate * Returns: 5897c478bd9Sstevel@tonic-gate * -1 - An error occurred. The error status is set. 5907c478bd9Sstevel@tonic-gate * >= 0 - The number of certs that were copied. 5917c478bd9Sstevel@tonic-gate */ 5927c478bd9Sstevel@tonic-gate int 5937c478bd9Sstevel@tonic-gate move_certs(STACK_OF(X509) *dst, STACK_OF(X509) *src) 5947c478bd9Sstevel@tonic-gate { 5957c478bd9Sstevel@tonic-gate X509 *tmpc; 5967c478bd9Sstevel@tonic-gate int count = 0; 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate while (sk_X509_num(src) > 0) { 5997c478bd9Sstevel@tonic-gate tmpc = sk_X509_delete(src, 0); 6007c478bd9Sstevel@tonic-gate if (sk_X509_push(dst, tmpc) == 0) { 6017c478bd9Sstevel@tonic-gate X509_free(tmpc); 6027c478bd9Sstevel@tonic-gate SUNWerr(SUNW_F_MOVE_CERTS, SUNW_R_MEMORY_FAILURE); 6037c478bd9Sstevel@tonic-gate return (-1); 6047c478bd9Sstevel@tonic-gate } 6057c478bd9Sstevel@tonic-gate count++; 6067c478bd9Sstevel@tonic-gate } 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate return (count); 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate /* 6127c478bd9Sstevel@tonic-gate * print_time - Given an ASN1_TIME, print one or both of the times. 6137c478bd9Sstevel@tonic-gate * 6147c478bd9Sstevel@tonic-gate * Arguments: 6157c478bd9Sstevel@tonic-gate * fp - File to write to 6167c478bd9Sstevel@tonic-gate * t - The time to format and print. 6177c478bd9Sstevel@tonic-gate * 6187c478bd9Sstevel@tonic-gate * Returns: 6197c478bd9Sstevel@tonic-gate * 0 - Error occurred while opening or writing. 6207c478bd9Sstevel@tonic-gate * > 0 - Success. 6217c478bd9Sstevel@tonic-gate */ 6227c478bd9Sstevel@tonic-gate int 6237c478bd9Sstevel@tonic-gate print_time(FILE *fp, ASN1_TIME *t) 6247c478bd9Sstevel@tonic-gate { 6257c478bd9Sstevel@tonic-gate BIO *bp; 6267c478bd9Sstevel@tonic-gate int ret = 1; 6277c478bd9Sstevel@tonic-gate 6287c478bd9Sstevel@tonic-gate if ((bp = BIO_new(BIO_s_file())) == NULL) { 6297c478bd9Sstevel@tonic-gate return (0); 6307c478bd9Sstevel@tonic-gate } 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate (void) BIO_set_fp(bp, fp, BIO_NOCLOSE); 6337c478bd9Sstevel@tonic-gate ret = ASN1_TIME_print(bp, t); 6347c478bd9Sstevel@tonic-gate (void) BIO_free(bp); 6357c478bd9Sstevel@tonic-gate 6367c478bd9Sstevel@tonic-gate return (ret); 6377c478bd9Sstevel@tonic-gate } 638