📄 x509.c
字号:
/* Support of X.509 certificates and CRLs * Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann * Copyright (C) 2001 Marco Bertossa, Andreas Schleiss * Copyright (C) 2002 Mario Strasser * Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * RCSID $Id: x509.c,v 1.23 2004/09/08 17:16:52 ken Exp $ */#include <stdlib.h>#include <stdio.h>#include <string.h>#include <unistd.h>#include <dirent.h>#include <time.h>#include <sys/types.h>#include <openswan.h>#include <openswan/ipsec_policy.h>#include <sys/queue.h>#include "constants.h"#include "oswlog.h"#include "defs.h"#include "log.h"#include "id.h"#include "asn1.h"#include "oid.h"#include "x509.h"#include "pgp.h"#include "certs.h"#include "keys.h"#include "packet.h"#include "demux.h" /* needs packet.h */#include "connections.h"#include "state.h"#include "md2.h"#include "md5.h"#include "sha1.h"#include "whack.h"#include "fetch.h"#include "ocsp.h"#include "pkcs.h"#include "x509more.h"#include "paths.h"/* chained lists of X.509 host/user and ca certificates and crls */static x509cert_t *x509certs = NULL;static x509cert_t *x509authcerts = NULL;static x509crl_t *x509crls = NULL;/* ASN.1 definition of a basicConstraints extension */static const asn1Object_t basicConstraintsObjects[] = { { 0, "basicConstraints", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ { 1, "CA", ASN1_BOOLEAN, ASN1_DEF | ASN1_BODY }, /* 1 */ { 1, "pathLenConstraint", ASN1_INTEGER, ASN1_OPT | ASN1_BODY }, /* 2 */ { 1, "end opt", ASN1_EOC, ASN1_END } /* 3 */};#define BASIC_CONSTRAINTS_CA 1#define BASIC_CONSTRAINTS_ROOF 4/* ASN.1 definition of time */static const asn1Object_t timeObjects[] = { { 0, "utcTime", ASN1_UTCTIME, ASN1_OPT | ASN1_BODY }, /* 0 */ { 0, "end opt", ASN1_EOC, ASN1_END }, /* 1 */ { 0, "generalizeTime", ASN1_GENERALIZEDTIME, ASN1_OPT | ASN1_BODY }, /* 2 */ { 0, "end opt", ASN1_EOC, ASN1_END } /* 3 */};#define TIME_UTC 0#define TIME_GENERALIZED 2#define TIME_ROOF 4/* ASN.1 definiton of an algorithmIdentifier */static const asn1Object_t algorithmIdentifierObjects[] = { { 0, "algorithmIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ { 1, "algorithm", ASN1_OID, ASN1_BODY } /* 1 */};#define ALGORITHM_IDENTIFIER_ALG 1#define ALGORITHM_IDENTIFIER_ROOF 2/* ASN.1 definition of a keyIdentifier */static const asn1Object_t keyIdentifierObjects[] = { { 0, "keyIdentifier", ASN1_OCTET_STRING, ASN1_BODY } /* 0 */};/* ASN.1 definition of a authorityKeyIdentifier extension */static const asn1Object_t authorityKeyIdentifierObjects[] = { { 0, "authorityKeyIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ { 1, "keyIdentifier", ASN1_CONTEXT_S_0, ASN1_OPT | ASN1_OBJ }, /* 1 */ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */ { 1, "authorityCertIssuer", ASN1_CONTEXT_C_1, ASN1_OPT | ASN1_OBJ }, /* 3 */ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 4 */ { 1, "authorityCertSerialNumber", ASN1_CONTEXT_S_2, ASN1_OPT | ASN1_BODY }, /* 5 */ { 1, "end opt", ASN1_EOC, ASN1_END } /* 6 */};#define AUTH_KEY_ID_KEY_ID 1#define AUTH_KEY_ID_CERT_ISSUER 3#define AUTH_KEY_ID_CERT_SERIAL 5#define AUTH_KEY_ID_ROOF 7/* ASN.1 definition of a authorityInfoAccess extension */static const asn1Object_t authorityInfoAccessObjects[] = { { 0, "authorityInfoAccess", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ { 1, "accessDescription", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ { 2, "accessMethod", ASN1_OID, ASN1_BODY }, /* 2 */ { 2, "accessLocation", ASN1_EOC, ASN1_RAW }, /* 3 */ { 0, "end loop", ASN1_EOC, ASN1_END } /* 4 */};#define AUTH_INFO_ACCESS_METHOD 2#define AUTH_INFO_ACCESS_LOCATION 3#define AUTH_INFO_ACCESS_ROOF 5/* ASN.1 definition of a extendedKeyUsage extension */static const asn1Object_t extendedKeyUsageObjects[] = { { 0, "extendedKeyUsage", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ { 1, "keyPurposeID", ASN1_OID, ASN1_BODY }, /* 1 */ { 0, "end loop", ASN1_EOC, ASN1_END }, /* 2 */};#define EXT_KEY_USAGE_PURPOSE_ID 1#define EXT_KEY_USAGE_ROOF 3/* ASN.1 definition of generalNames */static const asn1Object_t generalNamesObjects[] = { { 0, "generalNames", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ { 1, "generalName", ASN1_EOC, ASN1_RAW }, /* 1 */ { 0, "end loop", ASN1_EOC, ASN1_END } /* 2 */};#define GENERAL_NAMES_GN 1#define GENERAL_NAMES_ROOF 3/* ASN.1 definition of generalName */static const asn1Object_t generalNameObjects[] = { { 0, "otherName", ASN1_CONTEXT_C_0, ASN1_OPT | ASN1_BODY }, /* 0 */ { 0, "end choice", ASN1_EOC, ASN1_END }, /* 1 */ { 0, "rfc822Name", ASN1_CONTEXT_S_1, ASN1_OPT | ASN1_BODY }, /* 2 */ { 0, "end choice", ASN1_EOC, ASN1_END }, /* 3 */ { 0, "dnsName", ASN1_CONTEXT_S_2, ASN1_OPT | ASN1_BODY }, /* 4 */ { 0, "end choice", ASN1_EOC, ASN1_END }, /* 5 */ { 0, "x400Address", ASN1_CONTEXT_S_3, ASN1_OPT | ASN1_BODY }, /* 6 */ { 0, "end choice", ASN1_EOC, ASN1_END }, /* 7 */ { 0, "directoryName", ASN1_CONTEXT_C_4, ASN1_OPT | ASN1_BODY }, /* 8 */ { 0, "end choice", ASN1_EOC, ASN1_END }, /* 9 */ { 0, "ediPartyName", ASN1_CONTEXT_C_5, ASN1_OPT | ASN1_BODY }, /* 10 */ { 0, "end choice", ASN1_EOC, ASN1_END }, /* 11 */ { 0, "uniformResourceIdentifier", ASN1_CONTEXT_S_6, ASN1_OPT | ASN1_BODY }, /* 12 */ { 0, "end choice", ASN1_EOC, ASN1_END }, /* 13 */ { 0, "ipAddress", ASN1_CONTEXT_S_7, ASN1_OPT | ASN1_BODY }, /* 14 */ { 0, "end choice", ASN1_EOC, ASN1_END }, /* 15 */ { 0, "registeredID", ASN1_CONTEXT_S_8, ASN1_OPT | ASN1_BODY }, /* 16 */ { 0, "end choice", ASN1_EOC, ASN1_END } /* 17 */};#define GN_OBJ_OTHER_NAME 0#define GN_OBJ_RFC822_NAME 2#define GN_OBJ_DNS_NAME 4#define GN_OBJ_X400_ADDRESS 6#define GN_OBJ_DIRECTORY_NAME 8#define GN_OBJ_EDI_PARTY_NAME 10#define GN_OBJ_URI 12#define GN_OBJ_IP_ADDRESS 14#define GN_OBJ_REGISTERED_ID 16#define GN_OBJ_ROOF 18/* ASN.1 definition of crlDistributionPoints */static const asn1Object_t crlDistributionPointsObjects[] = { { 0, "crlDistributionPoints", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ { 1, "DistributionPoint", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ { 2, "distributionPoint", ASN1_CONTEXT_C_0, ASN1_OPT | ASN1_LOOP }, /* 2 */ { 3, "fullName", ASN1_CONTEXT_C_0, ASN1_OPT | ASN1_OBJ }, /* 3 */ { 3, "end choice", ASN1_EOC, ASN1_END }, /* 4 */ { 3, "nameRelativeToCRLIssuer", ASN1_CONTEXT_C_1, ASN1_OPT | ASN1_BODY }, /* 5 */ { 3, "end choice", ASN1_EOC, ASN1_END }, /* 6 */ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 7 */ { 2, "reasons", ASN1_CONTEXT_C_1, ASN1_OPT | ASN1_BODY }, /* 8 */ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 9 */ { 2, "crlIssuer", ASN1_CONTEXT_C_2, ASN1_OPT | ASN1_BODY }, /* 10 */ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 11 */ { 0, "end loop", ASN1_EOC, ASN1_END }, /* 12 */};#define CRL_DIST_POINTS_FULLNAME 3#define CRL_DIST_POINTS_ROOF 13/* ASN.1 definition of an X.509v3 certificate */static const asn1Object_t certObjects[] = { { 0, "certificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ { 1, "tbsCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ { 2, "DEFAULT v1", ASN1_CONTEXT_C_0, ASN1_DEF }, /* 2 */ { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */ { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 4 */ { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 5 */ { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */ { 2, "validity", ASN1_SEQUENCE, ASN1_NONE }, /* 7 */ { 3, "notBefore", ASN1_EOC, ASN1_RAW }, /* 8 */ { 3, "notAfter", ASN1_EOC, ASN1_RAW }, /* 9 */ { 2, "subject", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */ { 2, "subjectPublicKeyInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 11 */ { 3, "algorithm", ASN1_EOC, ASN1_RAW }, /* 12 */ { 3, "subjectPublicKey", ASN1_BIT_STRING, ASN1_NONE }, /* 13 */ { 4, "RSAPublicKey", ASN1_SEQUENCE, ASN1_NONE }, /* 14 */ { 5, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 15 */ { 5, "publicExponent", ASN1_INTEGER, ASN1_BODY }, /* 16 */ { 2, "issuerUniqueID", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 17 */ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 18 */ { 2, "subjectUniqueID", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 19 */ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 20 */ { 2, "optional extensions", ASN1_CONTEXT_C_3, ASN1_OPT }, /* 21 */ { 3, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 22 */ { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 23 */ { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 24 */ { 5, "critical", ASN1_BOOLEAN, ASN1_DEF | ASN1_BODY }, /* 25 */ { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 26 */ { 3, "end loop", ASN1_EOC, ASN1_END }, /* 27 */ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 28 */ { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 29 */ { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 30 */};#define X509_OBJ_CERTIFICATE 0#define X509_OBJ_TBS_CERTIFICATE 1#define X509_OBJ_VERSION 3#define X509_OBJ_SERIAL_NUMBER 4#define X509_OBJ_SIG_ALG 5#define X509_OBJ_ISSUER 6#define X509_OBJ_NOT_BEFORE 8#define X509_OBJ_NOT_AFTER 9#define X509_OBJ_SUBJECT 10#define X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM 12#define X509_OBJ_SUBJECT_PUBLIC_KEY 13#define X509_OBJ_MODULUS 15#define X509_OBJ_PUBLIC_EXPONENT 16#define X509_OBJ_EXTN_ID 24#define X509_OBJ_CRITICAL 25#define X509_OBJ_EXTN_VALUE 26#define X509_OBJ_ALGORITHM 29#define X509_OBJ_SIGNATURE 30#define X509_OBJ_ROOF 31/* ASN.1 definition of an X.509 certificate list */static const asn1Object_t crlObjects[] = { { 0, "certificateList", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ { 1, "tbsCertList", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ { 2, "version", ASN1_INTEGER, ASN1_OPT | ASN1_BODY }, /* 2 */ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 3 */ { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 4 */ { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */ { 2, "thisUpdate", ASN1_EOC, ASN1_RAW }, /* 6 */ { 2, "nextUpdate", ASN1_EOC, ASN1_RAW }, /* 7 */ { 2, "revokedCertificates", ASN1_SEQUENCE, ASN1_OPT | ASN1_LOOP }, /* 8 */ { 3, "certList", ASN1_SEQUENCE, ASN1_NONE }, /* 9 */ { 4, "userCertificate", ASN1_INTEGER, ASN1_BODY }, /* 10 */ { 4, "revocationDate", ASN1_EOC, ASN1_RAW }, /* 11 */ { 4, "crlEntryExtensions", ASN1_SEQUENCE, ASN1_OPT | ASN1_LOOP }, /* 12 */ { 5, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */ { 6, "extnID", ASN1_OID, ASN1_BODY }, /* 14 */ { 6, "critical", ASN1_BOOLEAN, ASN1_DEF | ASN1_BODY }, /* 15 */ { 6, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 16 */ { 4, "end opt or loop", ASN1_EOC, ASN1_END }, /* 17 */ { 2, "end opt or loop", ASN1_EOC, ASN1_END }, /* 18 */ { 2, "optional extensions", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 19 */ { 3, "crlExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 20 */ { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 21 */ { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 22 */ { 5, "critical", ASN1_BOOLEAN, ASN1_DEF | ASN1_BODY }, /* 23 */ { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 24 */ { 3, "end loop", ASN1_EOC, ASN1_END }, /* 25 */ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 26 */ { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 27 */ { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 28 */ };#define CRL_OBJ_CERTIFICATE_LIST 0#define CRL_OBJ_TBS_CERT_LIST 1#define CRL_OBJ_VERSION 2#define CRL_OBJ_SIG_ALG 4#define CRL_OBJ_ISSUER 5#define CRL_OBJ_THIS_UPDATE 6#define CRL_OBJ_NEXT_UPDATE 7#define CRL_OBJ_USER_CERTIFICATE 10#define CRL_OBJ_REVOCATION_DATE 11#define CRL_OBJ_CRL_ENTRY_CRITICAL 15#define CRL_OBJ_EXTN_ID 22#define CRL_OBJ_CRITICAL 23#define CRL_OBJ_EXTN_VALUE 24#define CRL_OBJ_ALGORITHM 27#define CRL_OBJ_SIGNATURE 28#define CRL_OBJ_ROOF 29const x509cert_t empty_x509cert = { NULL , /* *next */ UNDEFINED_TIME, /* installed */ 0 , /* count */ FALSE , /* smartcard */ AUTH_NONE , /* authority_flags */ { NULL, 0 } , /* certificate */ { NULL, 0 } , /* tbsCertificate */ 1 , /* version */ { NULL, 0 } , /* serialNumber */ OID_UNKNOWN , /* sigAlg */ { NULL, 0 } , /* issuer */ /* validity */ 0 , /* notBefore */ 0 , /* notAfter */ { NULL, 0 } , /* subject */ /* subjectPublicKeyInfo */ OID_UNKNOWN , /* subjectPublicKeyAlgorithm */ /* subjectPublicKey */ { NULL, 0 } , /* modulus */ { NULL, 0 } , /* publicExponent */ /* issuerUniqueID */ /* subjectUniqueID */ /* extensions */ /* extension */ /* extnID */ /* critical */ /* extnValue */ FALSE , /* isCA */ FALSE , /* isOcspSigner */ { NULL, 0 } , /* subjectKeyID */ { NULL, 0 } , /* authKeyID */ { NULL, 0 } , /* authKeySerialNumber */ { NULL, 0 } , /* accessLocation */ NULL , /* subjectAltName */ NULL , /* crlDistributionPoints */ OID_UNKNOWN , /* algorithm */ { NULL, 0 } /* signature */};const x509crl_t empty_x509crl = { NULL , /* *next */ UNDEFINED_TIME, /* installed */ NULL , /* distributionPoints */ { NULL, 0 } , /* certificateList */ { NULL, 0 } , /* tbsCertList */ 1 , /* version */ OID_UNKNOWN , /* sigAlg */ { NULL, 0 } , /* issuer */ UNDEFINED_TIME, /* thisUpdate */ UNDEFINED_TIME, /* nextUpdate */ NULL , /* revokedCertificates */ /* crlExtensions */ /* extension */ /* extnID */ /* critical */ /* extnValue */ { NULL, 0 } , /* authKeyID */ { NULL, 0 } , /* authKeySerialNumber */ OID_UNKNOWN , /* algorithm */ { NULL, 0 } /* signature */};/* coding of X.501 distinguished name */typedef struct { const u_char *name; chunk_t oid; u_char type;} x501rdn_t;/* X.501 acronyms for well known object identifiers (OIDs) */static u_char oid_ND[] = {0x02, 0x82, 0x06, 0x01, 0x0A, 0x07, 0x14};static u_char oid_UID[] = {0x09, 0x92, 0x26, 0x89, 0x93, 0xF2, 0x2C, 0x64, 0x01, 0x01};static u_char oid_DC[] = {0x09, 0x92, 0x26, 0x89, 0x93, 0xF2, 0x2C, 0x64, 0x01, 0x19};static u_char oid_CN[] = {0x55, 0x04, 0x03};static u_char oid_S[] = {0x55, 0x04, 0x04};static u_char oid_SN[] = {0x55, 0x04, 0x05};static u_char oid_C[] = {0x55, 0x04, 0x06};static u_char oid_L[] = {0x55, 0x04, 0x07};static u_char oid_ST[] = {0x55, 0x04, 0x08};static u_char oid_O[] = {0x55, 0x04, 0x0A};static u_char oid_OU[] = {0x55, 0x04, 0x0B};static u_char oid_T[] = {0x55, 0x04, 0x0C};static u_char oid_D[] = {0x55, 0x04, 0x0D};static u_char oid_N[] = {0x55, 0x04, 0x29};static u_char oid_G[] = {0x55, 0x04, 0x2A};static u_char oid_I[] = {0x55, 0x04, 0x2B};static u_char oid_ID[] = {0x55, 0x04, 0x2D};static u_char oid_E[] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x01};static u_char oid_TCGID[] = {0x2B, 0x06, 0x01, 0x04, 0x01, 0x89, 0x31, 0x01, 0x01, 0x02, 0x02, 0x4B};static const x501rdn_t x501rdns[] = { {"ND" , {oid_ND, 7}, ASN1_PRINTABLESTRING}, {"UID" , {oid_UID, 10}, ASN1_PRINTABLESTRING}, {"DC" , {oid_DC, 10}, ASN1_PRINTABLESTRING}, {"CN" , {oid_CN, 3}, ASN1_PRINTABLESTRING}, {"S" , {oid_S, 3}, ASN1_PRINTABLESTRING}, {"SN" , {oid_SN, 3}, ASN1_PRINTABLESTRING}, {"serialNumber" , {oid_SN, 3}, ASN1_PRINTABLESTRING}, {"C" , {oid_C, 3}, ASN1_PRINTABLESTRING}, {"L" , {oid_L, 3}, ASN1_PRINTABLESTRING}, {"ST" , {oid_ST, 3}, ASN1_PRINTABLESTRING}, {"O" , {oid_O, 3}, ASN1_PRINTABLESTRING}, {"OU" , {oid_OU, 3}, ASN1_PRINTABLESTRING}, {"T" , {oid_T, 3}, ASN1_PRINTABLESTRING}, {"D" , {oid_D, 3}, ASN1_PRINTABLESTRING}, {"N" , {oid_N, 3}, ASN1_PRINTABLESTRING}, {"G" , {oid_G, 3}, ASN1_PRINTABLESTRING}, {"I" , {oid_I, 3}, ASN1_PRINTABLESTRING}, {"ID" , {oid_ID, 3}, ASN1_PRINTABLESTRING}, {"E" , {oid_E, 9}, ASN1_IA5STRING}, {"Email" , {oid_E, 9}, ASN1_IA5STRING}, {"emailAddress" , {oid_E, 9}, ASN1_IA5STRING}, {"TCGID" , {oid_TCGID, 12}, ASN1_PRINTABLESTRING}};#define X501_RDN_ROOF 22/* Maximum length of ASN.1 distinquished name */#define BUF_LEN 512static voidupdate_chunk(chunk_t *ch, int n){ n = (n > -1 && n < (int)ch->len)? n : (int)ch->len-1; ch->ptr += n; ch->len -= n;}/* * Pointer is set to the first RDN in a DN */static err_tinit_rdn(chunk_t dn, chunk_t *rdn, chunk_t *attribute, bool *next){ *rdn = empty_chunk; *attribute = empty_chunk; /* a DN is a SEQUENCE OF RDNs */ if (*dn.ptr != ASN1_SEQUENCE) { return "DN is not a SEQUENCE"; } rdn->len = asn1_length(&dn); if (rdn->len == ASN1_INVALID_LENGTH) return "Invalid RDN length"; rdn->ptr = dn.ptr; /* are there any RDNs ? */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -