#include #include #include "asn1.h" #include "str.h" #include "textcode.h" struct x509signature { struct string oid; /* you are not expected to actually decode this */ size_t oididx; /* if this is (size_t)-1, then the parser did not know the OID. Otherwise it's the index into oid2string. oid2string[oididx].id should be something like X509_ALG_SHA1RSA (see asn1.h) */ struct string bitstring; /* In this string, the length is in bits, not bytes! */ /* If the length is not a multiple of 8, then the unused bits are missing in the last byte. * The parser already validated that the last byte is padded with 0 bits */ }; struct x509cert { enum { v1=0, v1988=0, v2=1, v3=2, v1996=2 } version; size_t serial; struct x509signature algid; struct string issuer; /* this is the raw asn.1 structure, a SET of "[{op}]" in scan_asn1generic terms */ time_t notbefore, notafter; struct string subject; /* this is the raw asn.1 structure, a SET of "[{op}]" in scan_asn1generic terms */ struct x509signature sig; }; void printasn1(const char* buf,const char* max); static int findindn(struct string* dn,enum x509_oid id,struct string* dest) { size_t i; const char* c=dn->s; const char* max=dn->s+dn->l; for (;;) { struct string oid; size_t l=scan_asn1generic(c,max,"[{op}]",&oid,dest); if (l) { i=lookupoid(oid.s,oid.l); if (i!=(size_t)-1) { // recognized the oid! if (oid2string[i].id==id) return 1; } c+=l; } else break; } return 0; } size_t scan_certificate(const char* cert,size_t l, struct x509cert* C) { char* c=0,* x; /* if it's base64 encoded, decode first */ if (l > 27+25+2 && str_start(cert,"-----BEGIN CERTIFICATE-----")) certfound: { size_t cur,used; /* "-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----" and newlines */ c=malloc((l-27-25-2)/4*3); if (!c) return 0; x=c; for (cur=27; cur+26'~')) { a=0; break; } if (str_start(cert+i,"-----BEGIN CERTIFICATE-----")) { cert+=i; l-=i; goto certfound; } } if (a) /* if we end up here, it was ascii but did not contain a certificate. fail. */ return 0; } /* if we end up here, we decoded some base64 data or we found some * binary data. See if it looks like x.509 at all. If it does, it * starts with a SEQUENCE_OF, which encodes as '0'. */ if (*cert!='0') { parseerror: free(c); return 0; } /* now for the heavy lifting */ { unsigned long tagforversion; // must be 0 unsigned long version; struct string oidalg,algparams,pubkeyalg,extensions,oidsig,sigrest,sigdata; size_t i; if (scan_asn1generic(cert,cert+l,"{{ci]i{o!}{!}{uu}{!}{!}!}{o!}b}", &tagforversion, &version, &C->serial, &oidalg, &algparams, &C->issuer, &C->notbefore, &C->notafter, &C->subject, &pubkeyalg, &extensions, &oidsig, &sigrest, &sigdata)) { if (version==0) printf("X.509 certificate\n"); else if (version==1) printf("X.509v2 certificate\n"); else if (version==2) printf("X.509v3 certificate\n"); else printf("unsupported version %ld (must be 0, 1 or 2)\n",version); printf("serial number %lu\n",C->serial); printf("issuer: "); { struct string s; if (findindn(&C->issuer,X509_ATTR_COUNTRY,&s)) printf("C=%.*s ",(int)s.l,s.s); if (findindn(&C->issuer,X509_ATTR_ORG,&s)) printf("O=%.*s ",(int)s.l,s.s); if (findindn(&C->issuer,X509_ATTR_COMMONNAME,&s)) printf("CN=%.*s ",(int)s.l,s.s); } printf("\n"); { char a[100],b[100]; a[fmt_httpdate(a,C->notbefore)]=0; b[fmt_httpdate(b,C->notafter)]=0; printf("valid not before %s and not after %s\n",a,b); } printf("subject: "); { struct string s; if (findindn(&C->issuer,X509_ATTR_COUNTRY,&s)) printf("C=%.*s ",(int)s.l,s.s); if (findindn(&C->issuer,X509_ATTR_ORG,&s)) printf("O=%.*s ",(int)s.l,s.s); if (findindn(&C->issuer,X509_ATTR_COMMONNAME,&s)) printf("CN=%.*s ",(int)s.l,s.s); } printf("\n"); i=lookupoid(oidalg.s,oidalg.l); if (i!=(size_t)-1) printf("signature algorithm %s\n",oid2string[i].name); else { unsigned long temp[100]; size_t len=100; if (scan_asn1rawoid(oidalg.s,oidalg.s+oidalg.l,temp,&len)) { printf("Unknown signature algorithm (oid "); for (i=0; i>((sizeof(modulus[0])*8)-(j+1)*8))&0xff); } if ((i-1)%4==3 || i==modulus[0]) printf("\n"); } } else printf("bignum scanning failed!\n"); } /* for RSA, bits is actually another sequence with two integers, modulus and publicExponent */ printf("pubkeyparams len %lu, bits len %lu\n",pubkeyparams.l,bits.l); } } else { unsigned long temp[100]; size_t len=100; if (scan_asn1rawoid(pubkeyoid.s,pubkeyoid.s+pubkeyoid.l,temp,&len)) { printf("Unknown public key algorithm (oid "); for (i=0; i #include "printasn1.c" int main(int argc,char* argv[]) { char* buf; size_t l,n; struct x509cert c; buf=mmap_read(argc>1?argv[1]:"test.pem",&l); if (!buf) { puts("test.pem not found"); return 1; } n=scan_certificate(buf,l,&c); }