📄 x509.c
字号:
goto errret; el = el->tl; key->p = mp = asn1mpint(&el->hd); if(mp == nil) goto errret; el = el->tl; key->kq = mp = asn1mpint(&el->hd); if(mp == nil) goto errret; el = el->tl; key->kp = mp = asn1mpint(&el->hd); if(mp == nil) goto errret; el = el->tl; key->c2 = mp = asn1mpint(&el->hd); if(mp == nil) goto errret; return key;errret: rsaprivfree(key); return nil;}static mpint*asn1mpint(Elem *e){ Bytes *b; mpint *mp; int v; if(is_int(e, &v)) return itomp(v, nil); if(is_bigint(e, &b)) { mp = betomp(b->data, b->len, nil); freebytes(b); return mp; } return nil;}static mpint*pkcs1pad(Bytes *b, mpint *modulus){ int n = (mpsignif(modulus)+7)/8; int pm1, i; uchar *p; mpint *mp; pm1 = n - 1 - b->len; p = (uchar*)emalloc(n); p[0] = 0; p[1] = 1; for(i = 2; i < pm1; i++) p[i] = 0xFF; p[pm1] = 0; memcpy(&p[pm1+1], b->data, b->len); mp = betomp(p, n, nil); free(p); return mp;}RSApriv*asn1toRSApriv(uchar *kd, int kn){ Bytes *b; RSApriv *key; b = makebytes(kd, kn); key = decode_rsaprivkey(b); freebytes(b); return key;}/* * digest(CertificateInfo) * Our ASN.1 library doesn't return pointers into the original * data array, so we need to do a little hand decoding. */static voiddigest_certinfo(Bytes *cert, DigestFun digestfun, uchar *digest){ uchar *info, *p, *pend; ulong infolen; int isconstr, length; Tag tag; Elem elem; p = cert->data; pend = cert->data + cert->len; if(tag_decode(&p, pend, &tag, &isconstr) != ASN_OK || tag.class != Universal || tag.num != SEQUENCE || length_decode(&p, pend, &length) != ASN_OK || p+length > pend || p+length < p) return; info = p; if(ber_decode(&p, pend, &elem) != ASN_OK) return; freevalfields(&elem.val); if(elem.tag.num != SEQUENCE) return; infolen = p - info; (*digestfun)(info, infolen, digest, nil);}static char*verify_signature(Bytes* signature, RSApub *pk, uchar *edigest, Elem **psigalg){ Elem e; Elist *el; Bytes *digest; uchar *pkcs1buf, *buf; int buflen; mpint *pkcs1; int nlen; char *err; err = nil; pkcs1buf = nil; /* one less than the byte length of the modulus */ nlen = (mpsignif(pk->n)-1)/8; /* see 9.2.1 of rfc2437 */ pkcs1 = betomp(signature->data, signature->len, nil); mpexp(pkcs1, pk->ek, pk->n, pkcs1); buflen = mptobe(pkcs1, nil, 0, &pkcs1buf); buf = pkcs1buf; if(buflen != nlen || buf[0] != 1) { err = "expected 1"; goto end; } buf++; while(buf[0] == 0xff) buf++; if(buf[0] != 0) { err = "expected 0"; goto end; } buf++; buflen -= buf-pkcs1buf; if(decode(buf, buflen, &e) != ASN_OK || !is_seq(&e, &el) || elistlen(el) != 2 || !is_octetstring(&el->tl->hd, &digest)) { err = "signature parse error"; goto end; } *psigalg = &el->hd; if(memcmp(digest->data, edigest, digest->len) == 0) goto end; err = "digests did not match";end: if(pkcs1 != nil) mpfree(pkcs1); if(pkcs1buf != nil) free(pkcs1buf); return err;} RSApub*X509toRSApub(uchar *cert, int ncert, char *name, int nname){ char *e; Bytes *b; CertX509 *c; RSApub *pk; b = makebytes(cert, ncert); c = decode_cert(b); freebytes(b); if(c == nil) return nil; if(name != nil && c->subject != nil){ e = strchr(c->subject, ','); if(e != nil) *e = 0; // take just CN part of Distinguished Name strncpy(name, c->subject, nname); } pk = decode_rsapubkey(c->publickey); freecert(c); return pk;}char*X509verify(uchar *cert, int ncert, RSApub *pk){ char *e; Bytes *b; CertX509 *c; uchar digest[SHA1dlen]; Elem *sigalg; b = makebytes(cert, ncert); c = decode_cert(b); if(c != nil) digest_certinfo(b, digestalg[c->signature_alg], digest); freebytes(b); if(c == nil) return "cannot decode cert"; e = verify_signature(c->signature, pk, digest, &sigalg); freecert(c); return e;}/* ------- Elem constructors ---------- */static ElemNull(void){ Elem e; e.tag.class = Universal; e.tag.num = NULLTAG; e.val.tag = VNull; return e;}static Elemmkint(int j){ Elem e; e.tag.class = Universal; e.tag.num = INTEGER; e.val.tag = VInt; e.val.u.intval = j; return e;}static Elemmkbigint(mpint *p){ Elem e; uchar *buf; int buflen; e.tag.class = Universal; e.tag.num = INTEGER; e.val.tag = VBigInt; buflen = mptobe(p, nil, 0, &buf); e.val.u.bigintval = makebytes(buf, buflen); free(buf); return e;}static Elemmkstring(char *s){ Elem e; e.tag.class = Universal; e.tag.num = IA5String; e.val.tag = VString; e.val.u.stringval = estrdup(s); return e;}static Elemmkoctet(uchar *buf, int buflen){ Elem e; e.tag.class = Universal; e.tag.num = OCTET_STRING; e.val.tag = VOctets; e.val.u.octetsval = makebytes(buf, buflen); return e;}static Elemmkbits(uchar *buf, int buflen){ Elem e; e.tag.class = Universal; e.tag.num = BIT_STRING; e.val.tag = VBitString; e.val.u.bitstringval = makebits(buf, buflen, 0); return e;}static Elemmkutc(long t){ Elem e; char utc[50]; Tm *tm = gmtime(t); e.tag.class = Universal; e.tag.num = UTCTime; e.val.tag = VString; snprint(utc, 50, "%.2d%.2d%.2d%.2d%.2d%.2dZ", tm->year % 100, tm->mon+1, tm->mday, tm->hour, tm->min, tm->sec); e.val.u.stringval = estrdup(utc); return e;}static Elemmkoid(Ints *oid){ Elem e; e.tag.class = Universal; e.tag.num = OBJECT_ID; e.val.tag = VObjId; e.val.u.objidval = makeints(oid->data, oid->len); return e;}static Elemmkseq(Elist *el){ Elem e; e.tag.class = Universal; e.tag.num = SEQUENCE; e.val.tag = VSeq; e.val.u.seqval = el; return e;}static Elemmkset(Elist *el){ Elem e; e.tag.class = Universal; e.tag.num = SETOF; e.val.tag = VSet; e.val.u.setval = el; return e;}static Elemmkalg(int alg){ return mkseq(mkel(mkoid(alg_oid_tab[alg]), mkel(Null(), nil)));}typedef struct Ints7pref { int len; int data[7]; char prefix[4];} Ints7pref;Ints7pref DN_oid[] = { {4, 2, 5, 4, 6, 0, 0, 0, "C="}, {4, 2, 5, 4, 8, 0, 0, 0, "ST="}, {4, 2, 5, 4, 7, 0, 0, 0, "L="}, {4, 2, 5, 4, 10, 0, 0, 0, "O="}, {4, 2, 5, 4, 11, 0, 0, 0, "OU="}, {4, 2, 5, 4, 3, 0, 0, 0, "CN="}, {7, 1,2,840,113549,1,9,1, "E="},};static Elemmkname(Ints7pref *oid, char *subj){ return mkset(mkel(mkseq(mkel(mkoid((Ints*)oid), mkel(mkstring(subj), nil))), nil));}static ElemmkDN(char *dn){ int i, j, nf; char *f[20], *prefix, *d2 = estrdup(dn); Elist* el = nil; nf = tokenize(d2, f, nelem(f)); for(i=nf-1; i>=0; i--){ for(j=0; j<nelem(DN_oid); j++){ prefix = DN_oid[j].prefix; if(strncmp(f[i],prefix,strlen(prefix))==0){ el = mkel(mkname(&DN_oid[j],f[i]+strlen(prefix)), el); break; } } } free(d2); return mkseq(el);}uchar*X509gen(RSApriv *priv, char *subj, ulong valid[2], int *certlen){ int serial = 0; uchar *cert = nil; RSApub *pk = rsaprivtopub(priv); Bytes *certbytes, *pkbytes, *certinfobytes, *sigbytes; Elem e, certinfo, issuer, subject, pubkey, validity, sig; uchar digest[MD5dlen], *buf; int buflen; mpint *pkcs1; e.val.tag = VInt; /* so freevalfields at errret is no-op */ issuer = mkDN(subj); subject = mkDN(subj); pubkey = mkseq(mkel(mkbigint(pk->n),mkel(mkint(mptoi(pk->ek)),nil))); if(encode(pubkey, &pkbytes) != ASN_OK) goto errret; freevalfields(&pubkey.val); pubkey = mkseq( mkel(mkalg(ALG_rsaEncryption), mkel(mkbits(pkbytes->data, pkbytes->len), nil))); freebytes(pkbytes); validity = mkseq( mkel(mkutc(valid[0]), mkel(mkutc(valid[1]), nil))); certinfo = mkseq( mkel(mkint(serial), mkel(mkalg(ALG_md5WithRSAEncryption), mkel(issuer, mkel(validity, mkel(subject, mkel(pubkey, nil))))))); if(encode(certinfo, &certinfobytes) != ASN_OK) goto errret; md5(certinfobytes->data, certinfobytes->len, digest, 0); freebytes(certinfobytes); sig = mkseq( mkel(mkalg(ALG_md5), mkel(mkoctet(digest, MD5dlen), nil))); if(encode(sig, &sigbytes) != ASN_OK) goto errret; pkcs1 = pkcs1pad(sigbytes, pk->n); freebytes(sigbytes); rsadecrypt(priv, pkcs1, pkcs1); buflen = mptobe(pkcs1, nil, 0, &buf); mpfree(pkcs1); e = mkseq( mkel(certinfo, mkel(mkalg(ALG_md5WithRSAEncryption), mkel(mkbits(buf, buflen), nil)))); free(buf); if(encode(e, &certbytes) != ASN_OK) goto errret; if(certlen) *certlen = certbytes->len; cert = certbytes->data;errret: freevalfields(&e.val); return cert;}uchar*X509req(RSApriv *priv, char *subj, int *certlen){ /* RFC 2314, PKCS #10 Certification Request Syntax */ int version = 0; uchar *cert = nil; RSApub *pk = rsaprivtopub(priv); Bytes *certbytes, *pkbytes, *certinfobytes, *sigbytes; Elem e, certinfo, subject, pubkey, sig; uchar digest[MD5dlen], *buf; int buflen; mpint *pkcs1; e.val.tag = VInt; /* so freevalfields at errret is no-op */ subject = mkDN(subj); pubkey = mkseq(mkel(mkbigint(pk->n),mkel(mkint(mptoi(pk->ek)),nil))); if(encode(pubkey, &pkbytes) != ASN_OK) goto errret; freevalfields(&pubkey.val); pubkey = mkseq( mkel(mkalg(ALG_rsaEncryption), mkel(mkbits(pkbytes->data, pkbytes->len), nil))); freebytes(pkbytes); certinfo = mkseq( mkel(mkint(version), mkel(subject, mkel(pubkey, nil)))); if(encode(certinfo, &certinfobytes) != ASN_OK) goto errret; md5(certinfobytes->data, certinfobytes->len, digest, 0); freebytes(certinfobytes); sig = mkseq( mkel(mkalg(ALG_md5), mkel(mkoctet(digest, MD5dlen), nil))); if(encode(sig, &sigbytes) != ASN_OK) goto errret; pkcs1 = pkcs1pad(sigbytes, pk->n); freebytes(sigbytes); rsadecrypt(priv, pkcs1, pkcs1); buflen = mptobe(pkcs1, nil, 0, &buf); mpfree(pkcs1); e = mkseq( mkel(certinfo, mkel(mkalg(ALG_md5), mkel(mkbits(buf, buflen), nil)))); free(buf); if(encode(e, &certbytes) != ASN_OK) goto errret; if(certlen) *certlen = certbytes->len; cert = certbytes->data;errret: freevalfields(&e.val); return cert;}static char*tagdump(Tag tag){ if(tag.class != Universal) return smprint("class%d,num%d", tag.class, tag.num); switch(tag.num){ case BOOLEAN: return "BOOLEAN"; case INTEGER: return "INTEGER"; case BIT_STRING: return "BIT STRING"; case OCTET_STRING: return "OCTET STRING"; case NULLTAG: return "NULLTAG"; case OBJECT_ID: return "OID"; case ObjectDescriptor: return "OBJECT_DES"; case EXTERNAL: return "EXTERNAL"; case REAL: return "REAL"; case ENUMERATED: return "ENUMERATED"; case EMBEDDED_PDV: return "EMBEDDED PDV"; case SEQUENCE: return "SEQUENCE"; case SETOF: return "SETOF"; case UTF8String: return "UTF8String"; case NumericString: return "NumericString"; case PrintableString: return "PrintableString"; case TeletexString: return "TeletexString"; case VideotexString: return "VideotexString"; case IA5String: return "IA5String"; case UTCTime: return "UTCTime"; case GeneralizedTime: return "GeneralizedTime"; case GraphicString: return "GraphicString"; case VisibleString: return "VisibleString"; case GeneralString: return "GeneralString"; case UniversalString: return "UniversalString"; case BMPString: return "BMPString"; default: return smprint("Universal,num%d", tag.num); }}static voidedump(Elem e){ Value v; Elist *el; int i; print("%s{", tagdump(e.tag)); v = e.val; switch(v.tag){ case VBool: print("Bool %d",v.u.boolval); break; case VInt: print("Int %d",v.u.intval); break; case VOctets: print("Octets[%d] %.2x%.2x...",v.u.octetsval->len,v.u.octetsval->data[0],v.u.octetsval->data[1]); break; case VBigInt: print("BigInt[%d] %.2x%.2x...",v.u.bigintval->len,v.u.bigintval->data[0],v.u.bigintval->data[1]); break; case VReal: print("Real..."); break; case VOther: print("Other..."); break; case VBitString: print("BitString..."); break; case VNull: print("Null"); break; case VEOC: print("EOC..."); break; case VObjId: print("ObjId"); for(i = 0; i<v.u.objidval->len; i++) print(" %d", v.u.objidval->data[i]); break; case VString: print("String \"%s\"",v.u.stringval); break; case VSeq: print("Seq\n"); for(el = v.u.seqval; el!=nil; el = el->tl) edump(el->hd); break; case VSet: print("Set\n"); for(el = v.u.setval; el!=nil; el = el->tl) edump(el->hd); break; } print("}\n");}voidasn1dump(uchar *der, int len){ Elem e; if(decode(der, len, &e) != ASN_OK){ print("didn't parse\n"); exits("didn't parse"); } edump(e);}voidX509dump(uchar *cert, int ncert){ char *e; Bytes *b; CertX509 *c; RSApub *pk; uchar digest[SHA1dlen]; Elem *sigalg; print("begin X509dump\n"); b = makebytes(cert, ncert); c = decode_cert(b); if(c != nil) digest_certinfo(b, digestalg[c->signature_alg], digest); freebytes(b); if(c == nil){ print("cannot decode cert"); return; } print("serial %d\n", c->serial); print("issuer %s\n", c->issuer); print("validity %s %s\n", c->validity_start, c->validity_end); print("subject %s\n", c->subject); pk = decode_rsapubkey(c->publickey); print("pubkey e=%B n(%d)=%B\n", pk->ek, mpsignif(pk->n), pk->n); print("sigalg=%d digest=%.*H\n", c->signature_alg, MD5dlen, digest); e = verify_signature(c->signature, pk, digest, &sigalg); if(e==nil){ e = "nil (meaning ok)"; print("sigalg=\n"); if(sigalg) edump(*sigalg); } print("self-signed verify_signature returns: %s\n", e); rsapubfree(pk); freecert(c); print("end X509dump\n");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -