6 /*=============================================================*/
7 /* general ASN1 declarations and parsing
9 * For now, this is used only for extracting the key from an
10 * X509 certificate, so the entire collection is hidden. But
11 * someday we should probably make the functions visible and
12 * give them their own man page.
14 typedef struct Elem Elem;
15 typedef struct Tag Tag;
16 typedef struct Value Value;
17 typedef struct Bytes Bytes;
18 typedef struct Ints Ints;
19 typedef struct Bits Bits;
20 typedef struct Elist Elist;
30 #define OCTET_STRING 4
33 #define ObjectDescriptor 7
37 #define EMBEDDED_PDV 11
39 #define SEQUENCE 16 /* also SEQUENCE OF */
40 #define SETOF 17 /* also SETOF OF */
41 #define NumericString 18
42 #define PrintableString 19
43 #define TeletexString 20
44 #define VideotexString 21
47 #define GeneralizedTime 24
48 #define GraphicString 25
49 #define VisibleString 26
50 #define GeneralString 27
51 #define UniversalString 28
65 int len; /* number of bytes */
66 int unusedbits; /* unused bits in last byte */
67 uchar data[]; /* most-significant bit first */
75 enum { VBool, VInt, VOctets, VBigInt, VReal, VOther,
76 VBitString, VNull, VEOC, VObjId, VString, VSeq, VSet };
78 int tag; /* VBool, etc. */
84 Bytes* realval; /* undecoded; hardly ever used */
91 } u; /* (Don't use anonymous unions, for ease of porting) */
104 /* decoding errors */
105 enum { ASN_OK, ASN_ESHORT, ASN_ETOOBIG, ASN_EVALLEN,
106 ASN_ECONSTR, ASN_EPRIM, ASN_EINVAL, ASN_EUNIMPL };
109 /* here are the functions to consider making extern someday */
110 static Bytes* newbytes(int len);
111 static Bytes* makebytes(uchar* buf, int len);
112 static void freebytes(Bytes* b);
113 static Bytes* catbytes(Bytes* b1, Bytes* b2);
114 static Ints* newints(int len);
115 static Ints* makeints(int* buf, int len);
116 static void freeints(Ints* b);
117 static Bits* newbits(int len);
118 static Bits* makebits(uchar* buf, int len, int unusedbits);
119 static void freebits(Bits* b);
120 static Elist* mkel(Elem e, Elist* tail);
121 static void freeelist(Elist* el);
122 static int elistlen(Elist* el);
123 static int is_seq(Elem* pe, Elist** pseq);
124 static int is_set(Elem* pe, Elist** pset);
125 static int is_int(Elem* pe, int* pint);
126 static int is_bigint(Elem* pe, Bytes** pbigint);
127 static int is_bitstring(Elem* pe, Bits** pbits);
128 static int is_octetstring(Elem* pe, Bytes** poctets);
129 static int is_oid(Elem* pe, Ints** poid);
130 static int is_string(Elem* pe, char** pstring);
131 static int is_time(Elem* pe, char** ptime);
132 static int decode(uchar* a, int alen, Elem* pelem);
133 static int decode_seq(uchar* a, int alen, Elist** pelist);
134 static int decode_value(uchar* a, int alen, int kind, int isconstr, Value* pval);
135 static int encode(Elem e, Bytes** pbytes);
136 static int oid_lookup(Ints* o, Ints** tab);
137 static void freevalfields(Value* v);
138 static mpint *asn1mpint(Elem *e);
142 #define TAG_MASK 0x1F
143 #define CONSTR_MASK 0x20
144 #define CLASS_MASK 0xC0
145 #define MAXOBJIDLEN 20
147 static int ber_decode(uchar** pp, uchar* pend, Elem* pelem);
148 static int tag_decode(uchar** pp, uchar* pend, Tag* ptag, int* pisconstr);
149 static int length_decode(uchar** pp, uchar* pend, int* plength);
150 static int value_decode(uchar** pp, uchar* pend, int length, int kind, int isconstr, Value* pval);
151 static int int_decode(uchar** pp, uchar* pend, int count, int unsgned, int* pint);
152 static int uint7_decode(uchar** pp, uchar* pend, int* pint);
153 static int octet_decode(uchar** pp, uchar* pend, int length, int isconstr, Bytes** pbytes);
154 static int seq_decode(uchar** pp, uchar* pend, int length, int isconstr, Elist** pelist);
155 static int enc(uchar** pp, Elem e, int lenonly);
156 static int val_enc(uchar** pp, Elem e, int *pconstr, int lenonly);
157 static void uint7_enc(uchar** pp, int num, int lenonly);
158 static void int_enc(uchar** pp, int num, int unsgned, int lenonly);
168 sysfatal("out of memory");
170 setmalloctag(p, getcallerpc(&n));
188 * Decode a[0..len] as a BER encoding of an ASN1 type.
189 * The return value is one of ASN_OK, etc.
190 * Depending on the error, the returned elem may or may not
194 decode(uchar* a, int alen, Elem* pelem)
198 return ber_decode(&p, &a[alen], pelem);
202 * Like decode, but continue decoding after first element
206 decode_seq(uchar* a, int alen, Elist** pelist)
210 return seq_decode(&p, &a[alen], -1, 1, pelist);
214 * Decode the whole array as a BER encoding of an ASN1 value,
215 * (i.e., the part after the tag and length).
216 * Assume the value is encoded as universal tag "kind".
217 * The constr arg is 1 if the value is constructed, 0 if primitive.
218 * If there's an error, the return string will contain the error.
219 * Depending on the error, the returned value may or may not
223 decode_value(uchar* a, int alen, int kind, int isconstr, Value* pval)
227 return value_decode(&p, &a[alen], alen, kind, isconstr, pval);
231 * All of the following decoding routines take arguments:
234 * Where parsing is supposed to start at **pp, and when parsing
235 * is done, *pp is updated to point at next char to be parsed.
236 * The pend pointer is just past end of string; an error should
237 * be returned parsing hasn't finished by then.
239 * The returned int is ASN_OK if all went fine, else ASN_ESHORT, etc.
240 * The remaining argument(s) are pointers to where parsed entity goes.
243 /* Decode an ASN1 'Elem' (tag, length, value) */
245 ber_decode(uchar** pp, uchar* pend, Elem* pelem)
253 err = tag_decode(pp, pend, &tag, &isconstr);
255 err = length_decode(pp, pend, &length);
257 if(tag.class == Universal)
258 err = value_decode(pp, pend, length, tag.num, isconstr, &val);
260 err = value_decode(pp, pend, length, OCTET_STRING, 0, &val);
270 /* Decode a tag field */
272 tag_decode(uchar** pp, uchar* pend, Tag* ptag, int* pisconstr)
282 ptag->class = v&CLASS_MASK;
289 err = uint7_decode(&p, pend, &v);
298 /* Decode a length field */
300 length_decode(uchar** pp, uchar* pend, int* plength)
313 err = int_decode(&p, pend, v&0x7F, 1, &num);
324 /* Decode a value field */
326 value_decode(uchar** pp, uchar* pend, int length, int kind, int isconstr, Value* pval)
332 int subids[MAXOBJIDLEN];
340 if(length == -1) { /* "indefinite" length spec */
344 else if(p + length > pend)
351 /* marker for end of indefinite constructions */
365 pval->u.boolval = (*p++ != 0);
373 else if(length <= 4) {
374 err = int_decode(&p, pend, length, 0, &num);
377 pval->u.intval = num;
382 pval->u.bigintval = makebytes(p, length);
388 pval->tag = VBitString;
390 if(length == -1 && p + 2 <= pend && *p == 0 && *(p+1) ==0) {
391 pval->u.bitstringval = makebits(0, 0, 0);
394 else /* TODO: recurse and concat results */
399 if(length == 1 && *p == 0) {
400 pval->u.bitstringval = makebits(0, 0, 0);
410 else if(length > 0x0FFFFFFF)
413 pval->u.bitstringval = makebits(p+1, length-1, bitsunused);
421 case ObjectDescriptor:
422 err = octet_decode(&p, pend, length, isconstr, &va);
425 pval->u.octetsval = va;
446 while(p < pe && isubid < MAXOBJIDLEN) {
447 err = uint7_decode(&p, pend, &num);
451 subids[isubid++] = num / 40;
452 subids[isubid++] = num % 40;
455 subids[isubid++] = num;
462 pval->u.objidval = makeints(subids, isubid);
470 /* TODO: parse this internally */
475 pval->u.otherval = makebytes(p, length);
481 /* Let the application decode */
484 else if(p+length > pend)
488 pval->u.realval = makebytes(p, length);
494 err = seq_decode(&p, pend, length, isconstr, &vl);
502 err = seq_decode(&p, pend, length, isconstr, &vl);
510 case PrintableString:
515 case GeneralizedTime:
519 case UniversalString:
521 /* TODO: figure out when character set conversion is necessary */
522 err = octet_decode(&p, pend, length, isconstr, &va);
525 pval->u.stringval = (char*)emalloc(va->len+1);
526 memmove(pval->u.stringval, va->data, va->len);
527 pval->u.stringval[va->len] = 0;
537 pval->u.otherval = makebytes(p, length);
547 * Decode an int in format where count bytes are
548 * concatenated to form value.
549 * Although ASN1 allows any size integer, we return
550 * an error if the result doesn't fit in a 32-bit int.
551 * If unsgned is not set, make sure to propagate sign bit.
554 int_decode(uchar** pp, uchar* pend, int count, int unsgned, int* pint)
563 if(p+count <= pend) {
564 if((count > 4) || (unsgned && count == 4 && (*p&0x80)))
567 if(!unsgned && count > 0 && count < 4 && (*p&0x80))
568 num = -1; /* set all bits, initially */
570 num = (num << 8)|(*p++);
581 * Decode an unsigned int in format where each
582 * byte except last has high bit set, and remaining
583 * seven bits of each byte are concatenated to form value.
584 * Although ASN1 allows any size integer, we return
585 * an error if the result doesn't fit in a 32 bit int.
588 uint7_decode(uchar** pp, uchar* pend, int* pint)
600 while(more && p < pend) {
618 * Decode an octet string, recursively if isconstr.
619 * We've already checked that length==-1 implies isconstr==1,
620 * and otherwise that specified length fits within (*pp..pend)
623 octet_decode(uchar** pp, uchar* pend, int length, int isconstr, Bytes** pbytes)
636 if(length >= 0 && !isconstr) {
637 ans = makebytes(p, length);
641 /* constructed, either definite or indefinite length */
644 if(length >= 0 && p >= pstart + length) {
645 if(p != pstart + length)
650 err = ber_decode(&p, pend, &elem);
653 switch(elem.val.tag) {
655 newans = catbytes(ans, elem.val.u.octetsval);
656 freevalfields(&elem.val);
666 freevalfields(&elem.val);
684 * Decode a sequence or set.
685 * We've already checked that length==-1 implies isconstr==1,
686 * and otherwise that specified length fits within (*p..pend)
689 seq_decode(uchar** pp, uchar* pend, int length, int isconstr, Elist** pelist)
706 /* constructed, either definite or indefinite length */
710 if(length >= 0 && p >= pstart + length) {
711 if(p != pstart + length)
716 err = ber_decode(&p, pend, &elem);
719 if(elem.val.tag == VEOC) {
727 lve = mkel(elem, lve);
732 /* reverse back to original order */
747 * Encode e by BER rules, putting answer in *pbytes.
748 * This is done by first calling enc with lenonly==1
749 * to get the length of the needed buffer,
750 * then allocating the buffer and using enc again to fill it up.
753 encode(Elem e, Bytes** pbytes)
763 ans = newbytes(p-&uc);
772 * The various enc functions take a pointer to a pointer
773 * into a buffer, and encode their entity starting there,
774 * updating the pointer afterwards.
775 * If lenonly is 1, only the pointer update is done,
776 * allowing enc to be called first to calculate the needed
778 * If lenonly is 0, it is assumed that the answer will fit.
782 enc(uchar** pp, Elem e, int lenonly)
794 err = val_enc(&p, e, &constr, 1);
800 v = tag.class|constr;
812 uint7_enc(&p, tag.num, lenonly);
821 int_enc(&p, vlen, 1, 1);
825 *p++ = (0x80 | ilen);
826 int_enc(&p, vlen, 1, 0);
832 val_enc(&p, e, &constr, 0);
840 val_enc(uchar** pp, Elem e, int *pconstr, int lenonly)
859 if(cl != Universal) {
889 kind = UniversalString;
904 int_enc(&p, v, 1, lenonly);
913 int_enc(&p, v, 0, lenonly);
915 if(is_bigint(&e, &bb)) {
917 memmove(p, bb->data, bb->len);
926 if(is_bitstring(&e, &bits)) {
933 v = bits->unusedbits;
939 memmove(p+1, bits->data, bits->len);
950 case ObjectDescriptor:
957 bb = e.val.u.octetsval;
960 bb = e.val.u.realval;
963 bb = e.val.u.otherval;
968 memmove(p, bb->data, bb->len);
979 if(is_oid(&e, &oid)) {
980 for(k = 0; k < oid->len; k++) {
987 uint7_enc(&p, v, lenonly);
997 if(e.val.tag == VSeq)
999 else if(e.val.tag == VSet)
1000 el = e.val.u.setval;
1004 *pconstr = CONSTR_MASK;
1005 for(; el != nil; el = el->tl) {
1006 err = enc(&p, el->hd, lenonly);
1015 case PrintableString:
1017 case VideotexString:
1020 case GeneralizedTime:
1024 case UniversalString:
1026 if(e.val.tag == VString) {
1027 s = e.val.u.stringval;
1047 * Encode num as unsigned 7 bit values with top bit 1 on all bytes
1048 * except last, only putting in bytes if !lenonly.
1051 uint7_enc(uchar** pp, int num, int lenonly)
1068 for(k = (n - 1)*7; k > 0; k -= 7)
1069 *p++= ((num >> k)|0x80);
1076 * Encode num as unsigned or signed integer,
1077 * only putting in bytes if !lenonly.
1078 * Encoding is length followed by bytes to concatenate.
1081 int_enc(uchar** pp, int num, int unsgned, int lenonly)
1101 if(!unsgned && (prevv&0x80))
1106 for(k = (n - 1)*8; k >= 0; k -= 8)
1113 ints_eq(Ints* a, Ints* b)
1121 for(i = 0; i < alen; i++)
1122 if(a->data[i] != b->data[i])
1128 * Look up o in tab (which must have nil entry to terminate).
1129 * Return index of matching entry, or -1 if none.
1132 oid_lookup(Ints* o, Ints** tab)
1136 for(i = 0; tab[i] != nil; i++)
1137 if(ints_eq(o, tab[i]))
1143 * Return true if *pe is a SEQUENCE, and set *pseq to
1144 * the value of the sequence if so.
1147 is_seq(Elem* pe, Elist** pseq)
1149 if(pe->tag.class == Universal && pe->tag.num == SEQUENCE && pe->val.tag == VSeq) {
1150 *pseq = pe->val.u.seqval;
1157 is_set(Elem* pe, Elist** pset)
1159 if(pe->tag.class == Universal && pe->tag.num == SETOF && pe->val.tag == VSet) {
1160 *pset = pe->val.u.setval;
1167 is_int(Elem* pe, int* pint)
1169 if(pe->tag.class == Universal) {
1170 if(pe->tag.num == INTEGER && pe->val.tag == VInt) {
1171 *pint = pe->val.u.intval;
1174 else if(pe->tag.num == BOOLEAN && pe->val.tag == VBool) {
1175 *pint = pe->val.u.boolval;
1183 * for convience, all VInt's are readable via this routine,
1184 * as well as all VBigInt's
1187 is_bigint(Elem* pe, Bytes** pbigint)
1191 if(pe->tag.class == Universal && pe->tag.num == INTEGER) {
1192 if(pe->val.tag == VBigInt)
1193 *pbigint = pe->val.u.bigintval;
1194 else if(pe->val.tag == VInt){
1195 v = pe->val.u.intval;
1196 for(n = 1; n < 4; n++)
1197 if((1 << (8 * n)) > v)
1199 *pbigint = newbytes(n);
1200 for(i = 0; i < n; i++)
1201 (*pbigint)->data[i] = (v >> ((n - 1 - i) * 8));
1210 is_bitstring(Elem* pe, Bits** pbits)
1212 if(pe->tag.class == Universal && pe->tag.num == BIT_STRING && pe->val.tag == VBitString) {
1213 *pbits = pe->val.u.bitstringval;
1220 is_octetstring(Elem* pe, Bytes** poctets)
1222 if(pe->tag.class == Universal && pe->tag.num == OCTET_STRING && pe->val.tag == VOctets) {
1223 *poctets = pe->val.u.octetsval;
1230 is_oid(Elem* pe, Ints** poid)
1232 if(pe->tag.class == Universal && pe->tag.num == OBJECT_ID && pe->val.tag == VObjId) {
1233 *poid = pe->val.u.objidval;
1240 is_string(Elem* pe, char** pstring)
1242 if(pe->tag.class == Universal) {
1243 switch(pe->tag.num) {
1246 case PrintableString:
1248 case VideotexString:
1253 case UniversalString:
1255 if(pe->val.tag == VString) {
1256 *pstring = pe->val.u.stringval;
1265 is_time(Elem* pe, char** ptime)
1267 if(pe->tag.class == Universal
1268 && (pe->tag.num == UTCTime || pe->tag.num == GeneralizedTime)
1269 && pe->val.tag == VString) {
1270 *ptime = pe->val.u.stringval;
1278 * malloc and return a new Bytes structure capable of
1279 * holding len bytes. (len >= 0)
1288 ans = emalloc(sizeof(Bytes) + len);
1294 * newbytes(len), with data initialized from buf
1297 makebytes(uchar* buf, int len)
1301 ans = newbytes(len);
1302 memmove(ans->data, buf, len);
1313 * Make a new Bytes, containing bytes of b1 followed by those of b2.
1314 * Either b1 or b2 or both can be nil.
1317 catbytes(Bytes* b1, Bytes* b2)
1326 ans = makebytes(b2->data, b2->len);
1328 else if(b2 == nil) {
1329 ans = makebytes(b1->data, b1->len);
1332 n = b1->len + b2->len;
1335 memmove(ans->data, b1->data, b1->len);
1336 memmove(ans->data+b1->len, b2->data, b2->len);
1341 /* len is number of ints */
1347 if(len < 0 || len > ((uint)-1>>1)/sizeof(int))
1349 ans = emalloc(sizeof(Ints) + len*sizeof(int));
1355 makeints(int* buf, int len)
1360 memmove(ans->data, buf, len*sizeof(int));
1370 /* len is number of bytes */
1378 ans = emalloc(sizeof(Bits) + len);
1380 ans->unusedbits = 0;
1385 makebits(uchar* buf, int len, int unusedbits)
1390 memmove(ans->data, buf, len);
1391 ans->unusedbits = unusedbits;
1402 mkel(Elem e, Elist* tail)
1406 el = (Elist*)emalloc(sizeof(Elist));
1407 setmalloctag(el, getcallerpc(&e));
1424 /* Frees elist, but not fields inside values of constituent elems */
1426 freeelist(Elist* el)
1437 /* free any allocated structures inside v (recursively freeing Elists) */
1439 freevalfields(Value* v)
1447 freebytes(v->u.octetsval);
1450 freebytes(v->u.bigintval);
1453 freebytes(v->u.realval);
1456 freebytes(v->u.otherval);
1459 freebits(v->u.bitstringval);
1462 freeints(v->u.objidval);
1466 free(v->u.stringval);
1470 for(l = el; l != nil; l = l->tl)
1471 freevalfields(&l->hd.val);
1476 for(l = el; l != nil; l = l->tl)
1477 freevalfields(&l->hd.val);
1483 /* end of general ASN1 functions */
1489 /*=============================================================*/
1491 * Decode and parse an X.509 Certificate, defined by this ASN1:
1492 * Certificate ::= SEQUENCE {
1493 * certificateInfo CertificateInfo,
1494 * signatureAlgorithm AlgorithmIdentifier,
1495 * signature BIT STRING }
1497 * CertificateInfo ::= SEQUENCE {
1498 * version [0] INTEGER DEFAULT v1 (0),
1499 * serialNumber INTEGER,
1500 * signature AlgorithmIdentifier,
1502 * validity Validity,
1504 * subjectPublicKeyInfo SubjectPublicKeyInfo }
1505 * (version v2 has two more fields, optional unique identifiers for
1506 * issuer and subject; since we ignore these anyway, we won't parse them)
1508 * Validity ::= SEQUENCE {
1509 * notBefore UTCTime,
1510 * notAfter UTCTime }
1512 * SubjectPublicKeyInfo ::= SEQUENCE {
1513 * algorithm AlgorithmIdentifier,
1514 * subjectPublicKey BIT STRING }
1516 * AlgorithmIdentifier ::= SEQUENCE {
1517 * algorithm OBJECT IDENTIFER,
1518 * parameters ANY DEFINED BY ALGORITHM OPTIONAL }
1520 * Name ::= SEQUENCE OF RelativeDistinguishedName
1522 * RelativeDistinguishedName ::= SETOF SIZE(1..MAX) OF AttributeTypeAndValue
1524 * AttributeTypeAndValue ::= SEQUENCE {
1525 * type OBJECT IDENTIFER,
1526 * value DirectoryString }
1527 * (selected attributes have these Object Ids:
1528 * commonName {2 5 4 3}
1529 * countryName {2 5 4 6}
1530 * localityName {2 5 4 7}
1531 * stateOrProvinceName {2 5 4 8}
1532 * organizationName {2 5 4 10}
1533 * organizationalUnitName {2 5 4 11}
1536 * DirectoryString ::= CHOICE {
1537 * teletexString TeletexString,
1538 * printableString PrintableString,
1539 * universalString UniversalString }
1541 * See rfc1423, rfc2437 for AlgorithmIdentifier, subjectPublicKeyInfo, signature.
1543 * Not yet implemented:
1544 * CertificateRevocationList ::= SIGNED SEQUENCE{
1545 * signature AlgorithmIdentifier,
1547 * lastUpdate UTCTime,
1548 * nextUpdate UTCTime,
1549 * revokedCertificates
1550 * SEQUENCE OF CRLEntry OPTIONAL}
1551 * CRLEntry ::= SEQUENCE{
1552 * userCertificate SerialNumber,
1553 * revocationDate UTCTime}
1556 typedef struct CertX509 {
1559 char* validity_start;
1568 /* Algorithm object-ids */
1571 ALG_md2WithRSAEncryption,
1572 ALG_md4WithRSAEncryption,
1573 ALG_md5WithRSAEncryption,
1575 ALG_sha1WithRSAEncryption,
1576 ALG_sha1WithRSAEncryptionOiw,
1578 ALG_sha256WithRSAEncryption,
1579 ALG_sha384WithRSAEncryption,
1580 ALG_sha512WithRSAEncryption,
1581 ALG_sha224WithRSAEncryption,
1593 typedef struct Ints15 {
1598 typedef struct DigestAlg {
1600 DigestState* (*fun)(uchar*,ulong,uchar*,DigestState*);
1604 static DigestAlg alg_md5 = { ALG_md5, md5, MD5dlen};
1605 static DigestAlg alg_sha1 = { ALG_sha1, sha1, SHA1dlen };
1606 static DigestAlg alg_sha256 = { ALG_sha256, sha2_256, SHA2_256dlen };
1607 static DigestAlg alg_sha384 = { ALG_sha384, sha2_384, SHA2_384dlen };
1608 static DigestAlg alg_sha512 = { ALG_sha512, sha2_512, SHA2_512dlen };
1609 static DigestAlg alg_sha224 = { ALG_sha224, sha2_224, SHA2_224dlen };
1611 /* maximum length of digest output of the digest algs above */
1613 MAXdlen = SHA2_512dlen,
1616 static Ints15 oid_rsaEncryption = {7, 1, 2, 840, 113549, 1, 1, 1 };
1617 static Ints15 oid_md2WithRSAEncryption = {7, 1, 2, 840, 113549, 1, 1, 2 };
1618 static Ints15 oid_md4WithRSAEncryption = {7, 1, 2, 840, 113549, 1, 1, 3 };
1619 static Ints15 oid_md5WithRSAEncryption = {7, 1, 2, 840, 113549, 1, 1, 4 };
1620 static Ints15 oid_sha1WithRSAEncryption ={7, 1, 2, 840, 113549, 1, 1, 5 };
1621 static Ints15 oid_sha1WithRSAEncryptionOiw ={6, 1, 3, 14, 3, 2, 29 };
1622 static Ints15 oid_sha256WithRSAEncryption = {7, 1, 2, 840, 113549, 1, 1, 11 };
1623 static Ints15 oid_sha384WithRSAEncryption = {7, 1, 2, 840, 113549, 1, 1, 12 };
1624 static Ints15 oid_sha512WithRSAEncryption = {7, 1, 2, 840, 113549, 1, 1, 13 };
1625 static Ints15 oid_sha224WithRSAEncryption = {7, 1, 2, 840, 113549, 1, 1, 14 };
1627 static Ints15 oid_md5 = {6, 1, 2, 840, 113549, 2, 5 };
1628 static Ints15 oid_sha1 = {6, 1, 3, 14, 3, 2, 26 };
1629 static Ints15 oid_sha256= {9, 2, 16, 840, 1, 101, 3, 4, 2, 1 };
1630 static Ints15 oid_sha384= {9, 2, 16, 840, 1, 101, 3, 4, 2, 2 };
1631 static Ints15 oid_sha512= {9, 2, 16, 840, 1, 101, 3, 4, 2, 3 };
1632 static Ints15 oid_sha224= {9, 2, 16, 840, 1, 101, 3, 4, 2, 4 };
1634 static Ints *alg_oid_tab[NUMALGS+1] = {
1635 (Ints*)&oid_rsaEncryption,
1636 (Ints*)&oid_md2WithRSAEncryption,
1637 (Ints*)&oid_md4WithRSAEncryption,
1638 (Ints*)&oid_md5WithRSAEncryption,
1640 (Ints*)&oid_sha1WithRSAEncryption,
1641 (Ints*)&oid_sha1WithRSAEncryptionOiw,
1643 (Ints*)&oid_sha256WithRSAEncryption,
1644 (Ints*)&oid_sha384WithRSAEncryption,
1645 (Ints*)&oid_sha512WithRSAEncryption,
1646 (Ints*)&oid_sha224WithRSAEncryption,
1657 static DigestAlg *digestalg[NUMALGS+1] = {
1658 &alg_md5, &alg_md5, &alg_md5, &alg_md5,
1659 &alg_sha1, &alg_sha1,
1660 &alg_sha256, &alg_sha384, &alg_sha512, &alg_sha224,
1661 &alg_md5, &alg_sha1, &alg_sha256, &alg_sha384, &alg_sha512, &alg_sha224,
1666 freecert(CertX509* c)
1671 free(c->validity_start);
1672 free(c->validity_end);
1674 freebytes(c->publickey);
1675 freebytes(c->signature);
1680 * Parse the Name ASN1 type.
1681 * The sequence of RelativeDistinguishedName's gives a sort of pathname,
1682 * from most general to most specific. Each element of the path can be
1683 * one or more (but usually just one) attribute-value pair, such as
1685 * We'll just form a "postal-style" address string by concatenating the elements
1686 * from most specific to least specific, separated by commas.
1687 * Return name-as-string (which must be freed by caller).
1698 enum { MAXPARTS = 100 };
1699 char* parts[MAXPARTS];
1710 if(!is_set(es, &esetl))
1712 while(esetl != nil) {
1714 if(!is_seq(eat, &eatl) || elistlen(eatl) != 2)
1716 if(!is_string(&eatl->tl->hd, &s) || i>=MAXPARTS)
1719 plen += strlen(s) + 2; /* room for ", " after */
1725 ans = (char*)emalloc(plen);
1740 * Parse an AlgorithmIdentifer ASN1 type.
1741 * Look up the oid in oid_tab and return one of OID_rsaEncryption, etc..,
1742 * or -1 if not found.
1743 * For now, ignore parameters, since none of our algorithms need them.
1751 if(!is_seq(e, &el) || el == nil || !is_oid(&el->hd, &oid))
1753 return oid_lookup(oid, alg_oid_tab);
1757 decode_cert(Bytes* a)
1772 Elist* elcert = nil;
1773 Elist* elcertinfo = nil;
1774 Elist* elvalidity = nil;
1775 Elist* elpubkey = nil;
1780 if(decode(a->data, a->len, &ecert) != ASN_OK)
1783 c = (CertX509*)emalloc(sizeof(CertX509));
1786 c->validity_start = nil;
1787 c->validity_end = nil;
1789 c->publickey_alg = -1;
1791 c->signature_alg = -1;
1795 if(!is_seq(&ecert, &elcert) || elistlen(elcert) !=3)
1797 ecertinfo = &elcert->hd;
1800 c->signature_alg = parse_alg(esigalg);
1804 /* Certificate Info */
1805 if(!is_seq(ecertinfo, &elcertinfo))
1807 n = elistlen(elcertinfo);
1810 eserial =&elcertinfo->hd;
1811 el = elcertinfo->tl;
1812 /* check for optional version, marked by explicit context tag 0 */
1813 if(eserial->tag.class == Context && eserial->tag.num == 0) {
1820 if(parse_alg(&el->hd) != c->signature_alg)
1825 evalidity = &el->hd;
1830 if(!is_int(eserial, &c->serial)) {
1831 if(!is_bigint(eserial, &b))
1833 c->serial = -1; /* else we have to change cert struct */
1835 c->issuer = parse_name(eissuer);
1836 if(c->issuer == nil)
1839 if(!is_seq(evalidity, &elvalidity))
1841 if(elistlen(elvalidity) != 2)
1843 e = &elvalidity->hd;
1844 if(!is_time(e, &c->validity_start))
1846 e->val.u.stringval = nil; /* string ownership transfer */
1847 e = &elvalidity->tl->hd;
1848 if(!is_time(e, &c->validity_end))
1850 e->val.u.stringval = nil; /* string ownership transfer */
1852 /* resume CertificateInfo */
1853 c->subject = parse_name(esubj);
1854 if(c->subject == nil)
1857 /* SubjectPublicKeyInfo */
1858 if(!is_seq(epubkey, &elpubkey))
1860 if(elistlen(elpubkey) != 2)
1863 c->publickey_alg = parse_alg(&elpubkey->hd);
1864 if(c->publickey_alg < 0)
1866 if(!is_bitstring(&elpubkey->tl->hd, &bits))
1868 if(bits->unusedbits != 0)
1870 c->publickey = makebytes(bits->data, bits->len);
1872 /*resume Certificate */
1873 if(c->signature_alg < 0)
1875 if(!is_bitstring(esig, &bits))
1877 c->signature = makebytes(bits->data, bits->len);
1881 freevalfields(&ecert.val); /* recurses through lists, too */
1890 * RSAPublickKey :: SEQUENCE {
1892 * publicExponent INTEGER
1896 decode_rsapubkey(Bytes* a)
1904 key = rsapuballoc();
1905 if(decode(a->data, a->len, &e) != ASN_OK)
1907 if(!is_seq(&e, &el) || elistlen(el) != 2)
1912 key->n = mp = asn1mpint(&el->hd);
1917 key->ek = mp = asn1mpint(&el->hd);
1930 * RSAPrivateKey ::= SEQUENCE {
1932 * modulus INTEGER, -- n
1933 * publicExponent INTEGER, -- e
1934 * privateExponent INTEGER, -- d
1935 * prime1 INTEGER, -- p
1936 * prime2 INTEGER, -- q
1937 * exponent1 INTEGER, -- d mod (p-1)
1938 * exponent2 INTEGER, -- d mod (q-1)
1939 * coefficient INTEGER -- (inverse of q) mod p }
1942 decode_rsaprivkey(Bytes* a)
1950 key = rsaprivalloc();
1951 if(decode(a->data, a->len, &e) != ASN_OK)
1953 if(!is_seq(&e, &el) || elistlen(el) != 9)
1955 if(!is_int(&el->hd, &version) || version != 0)
1959 key->pub.n = mp = asn1mpint(&el->hd);
1964 key->pub.ek = mp = asn1mpint(&el->hd);
1969 key->dk = mp = asn1mpint(&el->hd);
1974 key->q = mp = asn1mpint(&el->hd);
1979 key->p = mp = asn1mpint(&el->hd);
1984 key->kq = mp = asn1mpint(&el->hd);
1989 key->kp = mp = asn1mpint(&el->hd);
1994 key->c2 = mp = asn1mpint(&el->hd);
2005 * DSAPrivateKey ::= SEQUENCE{
2009 * g INTEGER, -- alpha
2010 * pub_key INTEGER, -- key
2011 * priv_key INTEGER, -- secret
2015 decode_dsaprivkey(Bytes* a)
2023 key = dsaprivalloc();
2024 if(decode(a->data, a->len, &e) != ASN_OK)
2026 if(!is_seq(&e, &el) || elistlen(el) != 6)
2029 if(!is_int(&el->hd, &version) || version != 0)
2031 fprint(2, "version %d\n", version);
2036 key->pub.p = mp = asn1mpint(&el->hd);
2041 key->pub.q = mp = asn1mpint(&el->hd);
2046 key->pub.alpha = mp = asn1mpint(&el->hd);
2051 key->pub.key = mp = asn1mpint(&el->hd);
2056 key->secret = mp = asn1mpint(&el->hd);
2074 return itomp(v, nil);
2075 if(is_bigint(e, &b)) {
2076 mp = betomp(b->data, b->len, nil);
2084 pkcs1padbuf(uchar *buf, int len, mpint *modulus)
2086 int n = (mpsignif(modulus)+7)/8;
2092 p = (uchar*)emalloc(n);
2095 for(i = 2; i < pm1; i++)
2098 memcpy(&p[pm1+1], buf, len);
2099 mp = betomp(p, n, nil);
2105 pkcs1pad(Bytes *b, mpint *modulus)
2107 return pkcs1padbuf(b->data, b->len, modulus);
2111 asn1toRSApriv(uchar *kd, int kn)
2116 b = makebytes(kd, kn);
2117 key = decode_rsaprivkey(b);
2123 asn1toDSApriv(uchar *kd, int kn)
2128 b = makebytes(kd, kn);
2129 key = decode_dsaprivkey(b);
2135 * digest(CertificateInfo)
2136 * Our ASN.1 library doesn't return pointers into the original
2137 * data array, so we need to do a little hand decoding.
2140 digest_certinfo(Bytes *cert, DigestAlg *da, uchar *digest)
2142 uchar *info, *p, *pend;
2144 int isconstr, length;
2149 pend = cert->data + cert->len;
2150 if(tag_decode(&p, pend, &tag, &isconstr) != ASN_OK ||
2151 tag.class != Universal || tag.num != SEQUENCE ||
2152 length_decode(&p, pend, &length) != ASN_OK ||
2157 if(ber_decode(&p, pend, &elem) != ASN_OK)
2159 freevalfields(&elem.val);
2160 if(elem.tag.num != SEQUENCE)
2163 (*da->fun)(info, infolen, digest, nil);
2168 pkcs1decryptsignature(uchar *sig, int siglen, RSApub *pk, uchar **pbuf)
2176 /* one less than the byte length of the modulus */
2177 nlen = (mpsignif(pk->n)-1)/8;
2179 /* see 9.2.1 of rfc2437 */
2180 pkcs1 = betomp(sig, siglen, nil);
2181 mpexp(pkcs1, pk->ek, pk->n, pkcs1);
2182 buflen = mptobe(pkcs1, nil, 0, pbuf);
2186 if(buflen != nlen || buf[0] != 1)
2189 while(buflen > 0 && buf[0] == 0xff)
2191 if(buflen < 1 || buf[0] != 0)
2194 memmove(*pbuf, buf, buflen);
2203 verify_digestinfo(uchar *sig, int siglen, RSApub *pk, uchar *pdigest, int *psigalg)
2213 memset(&e, 0, sizeof(e));
2214 buflen = pkcs1decryptsignature(sig, siglen, pk, &buf);
2215 if(buflen < 0 || decode(buf, buflen, &e) != ASN_OK || !is_seq(&e, &el) || elistlen(el) != 2 ||
2216 !is_octetstring(&el->tl->hd, &digest)) {
2217 err = "signature parse error";
2220 *psigalg = parse_alg(&el->hd);
2222 err = "unknown signature algorithm";
2225 if(digest->len != digestalg[*psigalg]->len){
2226 err = "bad digest length";
2229 memmove(pdigest, digest->data, digest->len);
2232 freevalfields(&e.val);
2238 X509verifydigest(uchar *sig, int siglen, uchar *edigest, int edigestlen, RSApub *pk)
2240 uchar digest[MAXdlen];
2244 e = verify_digestinfo(sig, siglen, pk, digest, &sigalg);
2247 if(digestalg[sigalg]->len != edigestlen)
2248 return "bad digest length";
2249 if(memcmp(digest, edigest, edigestlen) != 0)
2250 return "digests did not match";
2255 X509verifydata(uchar *sig, int siglen, uchar *data, int datalen, RSApub *pk)
2257 uchar digest[MAXdlen], edigest[MAXdlen];
2261 e = verify_digestinfo(sig, siglen, pk, digest, &sigalg);
2264 (*digestalg[sigalg]->fun)(data, datalen, edigest, nil);
2265 if(memcmp(digest, edigest, digestalg[sigalg]->len) != 0)
2266 return "digests did not match";
2271 X509toRSApub(uchar *cert, int ncert, char *name, int nname)
2278 b = makebytes(cert, ncert);
2283 if(name != nil && c->subject != nil){
2284 e = strchr(c->subject, ',');
2286 *e = 0; /* take just CN part of Distinguished Name */
2287 strncpy(name, c->subject, nname);
2289 pk = decode_rsapubkey(c->publickey);
2295 X509verify(uchar *cert, int ncert, RSApub *pk)
2301 uchar digest[MAXdlen];
2303 b = makebytes(cert, ncert);
2307 return "cannot decode cert";
2309 digestlen = digest_certinfo(b, digestalg[c->signature_alg], digest);
2313 return "cannot decode certinfo";
2315 e = X509verifydigest(c->signature->data, c->signature->len, digest, digestlen, pk);
2320 /* ------- Elem constructors ---------- */
2326 e.tag.class = Universal;
2327 e.tag.num = NULLTAG;
2337 e.tag.class = Universal;
2338 e.tag.num = INTEGER;
2351 e.tag.class = Universal;
2352 e.tag.num = INTEGER;
2353 e.val.tag = VBigInt;
2354 buflen = mptobe(p, nil, 0, &buf);
2355 e.val.u.bigintval = makebytes(buf, buflen);
2361 mkstring(char *s, int t)
2365 e.tag.class = Universal;
2367 e.val.tag = VString;
2368 e.val.u.stringval = estrdup(s);
2373 mkoctet(uchar *buf, int buflen)
2377 e.tag.class = Universal;
2378 e.tag.num = OCTET_STRING;
2379 e.val.tag = VOctets;
2380 e.val.u.octetsval = makebytes(buf, buflen);
2385 mkbits(uchar *buf, int buflen)
2389 e.tag.class = Universal;
2390 e.tag.num = BIT_STRING;
2391 e.val.tag = VBitString;
2392 e.val.u.bitstringval = makebits(buf, buflen, 0);
2403 e.tag.class = Universal;
2404 e.tag.num = UTCTime;
2405 e.val.tag = VString;
2406 snprint(utc, sizeof(utc), "%.2d%.2d%.2d%.2d%.2d%.2dZ",
2407 tm->year % 100, tm->mon+1, tm->mday, tm->hour, tm->min, tm->sec);
2408 e.val.u.stringval = estrdup(utc);
2417 e.tag.class = Universal;
2418 e.tag.num = OBJECT_ID;
2420 e.val.u.objidval = makeints(oid->data, oid->len);
2429 e.tag.class = Universal;
2430 e.tag.num = SEQUENCE;
2432 e.val.u.seqval = el;
2441 e.tag.class = Universal;
2444 e.val.u.setval = el;
2451 return mkseq(mkel(mkoid(alg_oid_tab[alg]), mkel(Null(), nil)));
2459 while((c = (uchar)*s++) != 0){
2460 if((c >= 'a' && c <= 'z')
2461 || (c >= 'A' && c <= 'Z')
2462 || (c >= '0' && c <= '9')
2463 || strchr("'=()+,-./:? ", c) != nil)
2470 typedef struct Ints7pref {
2476 Ints7pref DN_oid[] = {
2477 {4, 2, 5, 4, 6, 0, 0, 0, "C=", PrintableString},
2478 {4, 2, 5, 4, 8, 0, 0, 0, "ST=" },
2479 {4, 2, 5, 4, 7, 0, 0, 0, "L=" },
2480 {4, 2, 5, 4, 10, 0, 0, 0, "O=" },
2481 {4, 2, 5, 4, 11, 0, 0, 0, "OU=" },
2482 {4, 2, 5, 4, 3, 0, 0, 0, "CN=" },
2483 {7, 1,2,840,113549,1,9,1, "E=", IA5String},
2484 {7, 0,9,2342,19200300,100,1,25, "DC=",IA5String},
2488 mkname(Ints7pref *oid, char *subj)
2490 int stype = oid->stype ? oid->stype : (printable(subj) ? PrintableString : UTF8String);
2491 return mkset(mkel(mkseq(mkel(mkoid((Ints*)oid), mkel(mkstring(subj, stype), nil))), nil));
2498 char *f[20], *prefix, *d2 = estrdup(dn);
2501 nf = tokenize(d2, f, nelem(f));
2502 for(i=nf-1; i>=0; i--){
2503 for(j=0; j<nelem(DN_oid); j++){
2504 prefix = DN_oid[j].prefix;
2505 if(strncmp(f[i],prefix,strlen(prefix))==0){
2506 el = mkel(mkname(&DN_oid[j],f[i]+strlen(prefix)), el);
2516 X509encodesignature_sha256(uchar digest[SHA2_256dlen], uchar *buf, int len)
2523 mkel(mkalg(ALG_sha256),
2524 mkel(mkoctet(digest, SHA2_256dlen),
2526 err = encode(sig, &sigbytes);
2527 freevalfields(&sig.val);
2530 if(len < sigbytes->len){
2531 freebytes(sigbytes);
2534 len = sigbytes->len;
2535 memmove(buf, sigbytes->data, len);
2536 freebytes(sigbytes);
2542 X509gen(RSApriv *priv, char *subj, ulong valid[2], int *certlen)
2544 int serial = 0, sigalg = ALG_sha256WithRSAEncryption;
2546 RSApub *pk = rsaprivtopub(priv);
2547 Bytes *certbytes, *pkbytes, *certinfobytes, *sigbytes;
2550 uchar digest[MAXdlen], *buf;
2554 e = mkseq(mkel(mkbigint(pk->n),mkel(mkint(mptoi(pk->ek)),nil)));
2555 if(encode(e, &pkbytes) != ASN_OK)
2557 freevalfields(&e.val);
2563 mkel(mkutc(valid[0]),
2564 mkel(mkutc(valid[1]),
2568 mkel(mkalg(ALG_rsaEncryption),
2569 mkel(mkbits(pkbytes->data, pkbytes->len),
2573 if(encode(e, &certinfobytes) != ASN_OK)
2575 da = digestalg[sigalg];
2576 (*da->fun)(certinfobytes->data, certinfobytes->len, digest, 0);
2577 freebytes(certinfobytes);
2580 mkel(mkalg(da->alg),
2581 mkel(mkoctet(digest, da->len),
2583 if(encode(e, &sigbytes) != ASN_OK){
2584 freevalfields(&certinfo.val);
2587 freevalfields(&e.val);
2588 pkcs1 = pkcs1pad(sigbytes, pk->n);
2589 freebytes(sigbytes);
2590 rsadecrypt(priv, pkcs1, pkcs1);
2591 buflen = mptobe(pkcs1, nil, 0, &buf);
2596 mkel(mkbits(buf, buflen),
2599 if(encode(e, &certbytes) != ASN_OK)
2602 *certlen = certbytes->len;
2603 cert = malloc(certbytes->len);
2605 memmove(cert, certbytes->data, certbytes->len);
2606 freebytes(certbytes);
2608 freevalfields(&e.val);
2613 X509req(RSApriv *priv, char *subj, int *certlen)
2615 /* RFC 2314, PKCS #10 Certification Request Syntax */
2616 int version = 0, sigalg = ALG_sha256WithRSAEncryption;
2618 RSApub *pk = rsaprivtopub(priv);
2619 Bytes *certbytes, *pkbytes, *certinfobytes, *sigbytes;
2622 uchar digest[MAXdlen], *buf;
2626 e = mkseq(mkel(mkbigint(pk->n),mkel(mkint(mptoi(pk->ek)),nil)));
2627 if(encode(e, &pkbytes) != ASN_OK)
2629 freevalfields(&e.val);
2631 mkel(mkint(version),
2634 mkel(mkalg(ALG_rsaEncryption),
2635 mkel(mkbits(pkbytes->data, pkbytes->len),
2639 if(encode(e, &certinfobytes) != ASN_OK)
2641 da = digestalg[sigalg];
2642 (*da->fun)(certinfobytes->data, certinfobytes->len, digest, 0);
2643 freebytes(certinfobytes);
2646 mkel(mkalg(da->alg),
2647 mkel(mkoctet(digest, da->len),
2649 if(encode(e, &sigbytes) != ASN_OK){
2650 freevalfields(&certinfo.val);
2653 pkcs1 = pkcs1pad(sigbytes, pk->n);
2654 freebytes(sigbytes);
2655 rsadecrypt(priv, pkcs1, pkcs1);
2656 buflen = mptobe(pkcs1, nil, 0, &buf);
2661 mkel(mkbits(buf, buflen),
2664 if(encode(e, &certbytes) != ASN_OK)
2667 *certlen = certbytes->len;
2668 cert = malloc(certbytes->len);
2670 memmove(cert, certbytes->data, certbytes->len);
2671 freebytes(certbytes);
2673 freevalfields(&e.val);
2680 if(tag.class != Universal)
2681 return smprint("class%d,num%d", tag.class, tag.num);
2683 case BOOLEAN: return "BOOLEAN";
2684 case INTEGER: return "INTEGER";
2685 case BIT_STRING: return "BIT STRING";
2686 case OCTET_STRING: return "OCTET STRING";
2687 case NULLTAG: return "NULLTAG";
2688 case OBJECT_ID: return "OID";
2689 case ObjectDescriptor: return "OBJECT_DES";
2690 case EXTERNAL: return "EXTERNAL";
2691 case REAL: return "REAL";
2692 case ENUMERATED: return "ENUMERATED";
2693 case EMBEDDED_PDV: return "EMBEDDED PDV";
2694 case SEQUENCE: return "SEQUENCE";
2695 case SETOF: return "SETOF";
2696 case UTF8String: return "UTF8String";
2697 case NumericString: return "NumericString";
2698 case PrintableString: return "PrintableString";
2699 case TeletexString: return "TeletexString";
2700 case VideotexString: return "VideotexString";
2701 case IA5String: return "IA5String";
2702 case UTCTime: return "UTCTime";
2703 case GeneralizedTime: return "GeneralizedTime";
2704 case GraphicString: return "GraphicString";
2705 case VisibleString: return "VisibleString";
2706 case GeneralString: return "GeneralString";
2707 case UniversalString: return "UniversalString";
2708 case BMPString: return "BMPString";
2710 return smprint("Universal,num%d", tag.num);
2721 print("%s{", tagdump(e.tag));
2724 case VBool: print("Bool %d",v.u.boolval); break;
2725 case VInt: print("Int %d",v.u.intval); break;
2726 case VOctets: print("Octets[%d] %.2x%.2x...",v.u.octetsval->len,v.u.octetsval->data[0],v.u.octetsval->data[1]); break;
2727 case VBigInt: print("BigInt[%d] %.2x%.2x...",v.u.bigintval->len,v.u.bigintval->data[0],v.u.bigintval->data[1]); break;
2728 case VReal: print("Real..."); break;
2729 case VOther: print("Other..."); break;
2730 case VBitString: print("BitString..."); break;
2731 case VNull: print("Null"); break;
2732 case VEOC: print("EOC..."); break;
2733 case VObjId: print("ObjId");
2734 for(i = 0; i<v.u.objidval->len; i++)
2735 print(" %d", v.u.objidval->data[i]);
2737 case VString: print("String \"%s\"",v.u.stringval); break;
2738 case VSeq: print("Seq\n");
2739 for(el = v.u.seqval; el!=nil; el = el->tl)
2742 case VSet: print("Set\n");
2743 for(el = v.u.setval; el!=nil; el = el->tl)
2751 asn1dump(uchar *der, int len)
2755 if(decode(der, len, &e) != ASN_OK){
2756 print("didn't parse\n");
2757 exits("didn't parse");
2763 X509dump(uchar *cert, int ncert)
2770 uchar digest[MAXdlen];
2772 print("begin X509dump\n");
2773 b = makebytes(cert, ncert);
2777 print("cannot decode cert\n");
2780 digestlen = digest_certinfo(b, digestalg[c->signature_alg], digest);
2784 print("cannot decode certinfo\n");
2788 print("serial %d\n", c->serial);
2789 print("issuer %s\n", c->issuer);
2790 print("validity %s %s\n", c->validity_start, c->validity_end);
2791 print("subject %s\n", c->subject);
2792 pk = decode_rsapubkey(c->publickey);
2793 print("pubkey e=%B n(%d)=%B\n", pk->ek, mpsignif(pk->n), pk->n);
2795 print("sigalg=%d digest=%.*H\n", c->signature_alg, digestlen, digest);
2796 e = X509verifydigest(c->signature->data, c->signature->len, digest, digestlen, pk);
2798 e = "nil (meaning ok)";
2799 print("self-signed X509verifydigest returns: %s\n", e);
2803 print("end X509dump\n");