ref: 065d312a1728a00c7a12f8cc64f05b8b210d8426
dir: /libsec.diff/
diff 051804186780ef7f3b2f4cb548be1dd0685de5fe uncommitted
--- a/sys/include/libsec.h
+++ b/sys/include/libsec.h
@@ -1,7 +1,6 @@
#pragma lib "libsec.a"
#pragma src "/sys/src/libsec"
-
#ifndef _MPINT
typedef struct mpint mpint;
#endif
@@ -318,6 +317,7 @@
typedef struct RSApub RSApub;
typedef struct RSApriv RSApriv;
typedef struct PEMChain PEMChain;
+typedef struct CertX509 CertX509;
/* public/encryption key */
struct RSApub
@@ -347,6 +347,24 @@
int pemlen;
};
+struct CertX509 {
+ int serial;
+ char* issuer;
+ vlong validity_start;
+ vlong validity_end;
+ char* subject;
+ char** altsubject;
+ int naltsubject;
+ int publickey_alg;
+ void* publickey;
+ int signature_alg;
+ void* signature;
+ int curve;
+ void* ext;
+ uchar digest[SHA2_512dlen];
+ int digestlen;
+};
+
RSApriv* rsagen(int nlen, int elen, int rounds);
RSApriv* rsafill(mpint *n, mpint *e, mpint *d, mpint *p, mpint *q);
mpint* rsaencrypt(RSApub *k, mpint *in, mpint *out);
@@ -356,6 +374,9 @@
RSApriv* rsaprivalloc(void);
void rsaprivfree(RSApriv*);
RSApub* rsaprivtopub(RSApriv*);
+char* X509verify(CertX509*, CertX509*);
+CertX509* X509decode(uchar*, int);
+void X509free(CertX509*);
RSApub* X509toRSApub(uchar*, int, char*, int);
RSApub* X509reqtoRSApub(uchar*, int, char*, int);
RSApub* asn1toRSApub(uchar*, int);
@@ -368,7 +389,7 @@
char* X509rsaverify(uchar *cert, int ncert, RSApub *pk);
char* X509rsaverifydigest(uchar *sig, int siglen, uchar *edigest, int edigestlen, RSApub *pk);
-void X509dump(uchar *cert, int ncert);
+void X509dump(int fd, uchar *cert, int ncert);
mpint* pkcs1padbuf(uchar *buf, int len, mpint *modulus, int blocktype);
int pkcs1unpadbuf(uchar *buf, int len, mpint *modulus, int blocktype);
@@ -488,7 +509,51 @@
char *pskID;
} TLSconn;
+typedef struct TLSClientConf {
+ uchar *cert;
+ int ncert;
+ int noverify;
+ char *sessiontype;
+ int (*trace)(char*fmt, ...);
+ struct {
+ uchar *key;
+ int nkey;
+ char *id;
+ } psk;
+ struct {
+ int nkey;
+ char *constant;
+ } ttls;
+} TLSClientConf;
+
+typedef struct TLSServerConf {
+ PEMChain *certs;
+ char *sessiontype;
+ int (*trace)(char*fmt, ...);
+ struct {
+ uchar *key;
+ int nkey;
+ char *id;
+ } psk;
+ struct {
+ int nkey;
+ char *constant;
+ } ttls;
+} TLSServerConf;
+
+typedef struct TLSParams {
+ char dir[40]; /* connection directory */
+ PEMChain *certs;
+ struct {
+ uchar *key;
+ int nkey;
+ } ttls;
+} TLSParams;
+
/* tlshand.c */
+int tlsclient(int fd, char *srv, TLSClientConf *cfg, TLSParams **pparam);
+int tlsserver(int fd, TLSServerConf *cfg, TLSParams **pparam);
+void tlsparamfree(TLSParams *p);
int tlsClient(int fd, TLSconn *c);
int tlsServer(int fd, TLSconn *c);
--- a/sys/src/libsec/port/tlshand.c
+++ b/sys/src/libsec/port/tlshand.c
@@ -91,7 +91,8 @@
int erred; // set when tlsError called
int (*trace)(char*fmt, ...); // for debugging
int version; // protocol we are speaking
- Bytes *cert; // server certificate; only last - no chain
+ Bytes **certs; // server certificate; only last - no chain
+ int ncerts;
int cipher;
int nsecret; // amount of secret data to init keys
@@ -406,6 +407,8 @@
static Bytes* pkcs1_decrypt(TlsSec *sec, Bytes *data);
static Bytes* pkcs1_sign(TlsSec *sec, uchar *digest, int digestlen, int sigalg);
+static int validCert(char *rsrc, PEMChain *pc);
+
static void* emalloc(int);
static void* erealloc(void*, int);
static void put32(uchar *p, u32int);
@@ -424,6 +427,78 @@
//================= client/server ========================
+int
+tlsserver(int fd, TLSServerConf *cfg, TLSParams **pparam)
+{
+ char buf[8];
+ char dname[32];
+ uchar seed[2*RandomSize];
+ int n, data, ctl, hand;
+ TlsConnection *tls;
+ TLSParams *param;
+
+ param = emalloc(sizeof(TLSParams));
+ ctl = open("/net/tls/clone", ORDWR|OCEXEC);
+ if(ctl < 0)
+ return -1;
+ n = read(ctl, buf, sizeof(buf)-1);
+ if(n < 0){
+ close(ctl);
+ return -1;
+ }
+ buf[n] = 0;
+ snprint(param->dir, sizeof(param->dir), "/net/tls/%s", buf);
+ snprint(dname, sizeof(dname), "/net/tls/%s/hand", buf);
+ hand = open(dname, ORDWR|OCEXEC);
+ if(hand < 0){
+ close(ctl);
+ return -1;
+ }
+ data = -1;
+ fprint(ctl, "fd %d 0x%x", fd, ProtocolVersion);
+ tls = tlsServer2(ctl, hand,
+ cfg->certs->pem, cfg->certs->pemlen,
+ cfg->psk.id, cfg->psk.key, cfg->psk.nkey,
+ cfg->trace, cfg->certs->next);
+ if(tls != nil){
+ snprint(dname, sizeof(dname), "/net/tls/%s/data", buf);
+ data = open(dname, ORDWR);
+ }
+ close(hand);
+ close(ctl);
+ if(data < 0){
+ tlsparamfree(param);
+ tlsConnectionFree(tls);
+ return -1;
+ }
+ param->certs = nil; // client certificates are not yet implemented
+ if(cfg->sessiontype != nil){
+ if(strcmp(cfg->sessiontype, "ttls") != 0 || cfg->ttls.nkey == 0){
+ werrstr("invalid tls session: %s", cfg->sessiontype);
+ close(data);
+ tlsparamfree(param);
+ tlsConnectionFree(tls);
+ return -1;
+ }
+ param->ttls.key = emalloc(param->ttls.nkey);
+ memmove(seed, tls->sec->crandom, RandomSize);
+ memmove(seed+RandomSize, tls->sec->srandom, RandomSize);
+ tls->sec->prf(
+ param->ttls.key, param->ttls.nkey,
+ tls->sec->sec, MasterSecretSize,
+ cfg->ttls.constant,
+ seed, sizeof(seed));
+ }
+ tlsConnectionFree(tls);
+ close(fd);
+ if(pparam == nil)
+ tlsparamfree(param);
+ else
+ *pparam = param;
+ return data;
+
+}
+
// push TLS onto fd, returning new (application) file descriptor
// or -1 if error.
int
@@ -491,7 +566,7 @@
}
static uchar*
-tlsClientExtensions(TLSconn *conn, int *plen)
+tlsClientExtensions(char *srvname, int *plen)
{
uchar *b, *p;
int i, n, m;
@@ -499,7 +574,7 @@
p = b = nil;
// RFC6066 - Server Name Identification
- if(conn->serverName != nil && (n = strlen(conn->serverName)) > 0){
+ if(srvname != nil && (n = strlen(srvname)) > 0){
m = p - b;
b = erealloc(b, m + 2+2+2+1+2+n);
p = b + m;
@@ -509,7 +584,7 @@
put16(p, 1+2+n), p += 2; /* Server Name list length */
*p++ = 0; /* Server Name Type: host_name */
put16(p, n), p += 2; /* Server Name length */
- memmove(p, conn->serverName, n);
+ memmove(p, srvname, n);
p += n;
}
@@ -557,6 +632,118 @@
return b;
}
+int
+tlsclient(int fd, char *srvname, TLSClientConf *cfg, TLSParams **pparam)
+{
+ char buf[8];
+ char dname[32];
+ uchar seed[2*RandomSize];
+ int i, n, data, ctl, hand;
+ TlsConnection *tls;
+ TLSParams *param;
+ PEMChain *pc, **ppc;
+ uchar *ext;
+
+ param = emalloc(sizeof(TLSParams));
+ ctl = open("/net/tls/clone", ORDWR|OCEXEC);
+ if(ctl < 0)
+ return -1;
+ n = read(ctl, buf, sizeof(buf)-1);
+ if(n < 0){
+ close(ctl);
+ return -1;
+ }
+ buf[n] = 0;
+ snprint(param->dir, sizeof(param->dir), "/net/tls/%s", buf);
+ snprint(dname, sizeof(dname), "/net/tls/%s/hand", buf);
+ hand = open(dname, ORDWR|OCEXEC);
+ if(hand < 0){
+ close(ctl);
+ return -1;
+ }
+ snprint(dname, sizeof(dname), "/net/tls/%s/data", buf);
+ data = open(dname, ORDWR);
+ if(data < 0){
+ close(hand);
+ close(ctl);
+ return -1;
+ }
+ fprint(ctl, "fd %d 0x%x", fd, ProtocolVersion);
+ ext = tlsClientExtensions(srvname, &n);
+ tls = tlsClient2(ctl, hand,
+ cfg->cert, cfg->ncert,
+ cfg->psk.id, cfg->psk.key, cfg->psk.nkey,
+ ext, n, cfg->trace);
+ free(ext);
+ close(hand);
+ close(ctl);
+ if(tls == nil){
+ tlsparamfree(param);
+ close(data);
+ return -1;
+ }
+fprint(2, "certs: %#p, ncerts: %d\n", tls->certs, tls->ncerts);
+ if(tls->certs != nil){
+ ppc = ¶m->certs;
+ for(i = 0; i < tls->ncerts; i++){
+fprint(2, "add cert [%d]\n", i);
+ pc = emalloc(sizeof(PEMChain) + tls->certs[i]->len);
+ pc->next = nil;
+ pc->pem = (uchar*)(pc+1);
+ pc->pemlen = tls->certs[i]->len;
+ memcpy(pc->pem, tls->certs[i]->data, pc->pemlen);
+ *ppc = pc;
+ ppc = &pc->next;
+ }
+ } else {
+ param->certs = nil;
+ }
+ param->ttls.nkey = cfg->ttls.nkey;
+ if(cfg->sessiontype != nil){
+ if(strcmp(cfg->sessiontype, "ttls") != 0 || cfg->ttls.nkey == 0){
+ werrstr("invalid tls session: %s", cfg->sessiontype);
+ tlsparamfree(param);
+ close(data);
+ return -1;
+ }
+ param->ttls.key = emalloc(param->ttls.nkey);
+ memmove(seed, tls->sec->crandom, RandomSize);
+ memmove(seed+RandomSize, tls->sec->srandom, RandomSize);
+ tls->sec->prf(
+ param->ttls.key, param->ttls.nkey,
+ tls->sec->sec, MasterSecretSize,
+ cfg->ttls.constant,
+ seed, sizeof(seed));
+ }
+ tlsConnectionFree(tls);
+ close(fd);
+ if(cfg->noverify == 0
+ && cfg->psk.key == nil
+ && validCert("orib.dev", param->certs) == 0){
+ tlsparamfree(param);
+ close(data);
+ return -1;
+ }
+ if(pparam == nil)
+ tlsparamfree(param);
+ else
+ *pparam = param;
+ return data;
+}
+
+void
+tlsparamfree(TLSParams *param)
+{
+ PEMChain *pc, *pn;
+
+ for(pc = param->certs; pc != nil; pc = pn){
+ pn = pc->next;
+ free(pc);
+ }
+ free(param->ttls.key);
+ free(param);
+}
+
// push TLS onto fd, returning new (application) file descriptor
// or -1 if error.
int
@@ -595,7 +782,7 @@
return -1;
}
fprint(ctl, "fd %d 0x%x", fd, ProtocolVersion);
- ext = tlsClientExtensions(conn, &n);
+ ext = tlsClientExtensions(conn->serverName, &n);
tls = tlsClient2(ctl, hand,
conn->cert, conn->certlen,
conn->pskID, conn->psk, conn->psklen,
@@ -608,10 +795,10 @@
return -1;
}
free(conn->cert);
- if(tls->cert != nil){
- conn->certlen = tls->cert->len;
+ if(tls->certs != nil){
+ conn->certlen = tls->certs[0]->len;
conn->cert = emalloc(conn->certlen);
- memcpy(conn->cert, tls->cert->data, conn->certlen);
+ memcpy(conn->cert, tls->certs[0]->data, conn->certlen);
} else {
conn->certlen = 0;
conn->cert = nil;
@@ -1042,7 +1229,7 @@
uchar *ext, int extlen,
int (*trace)(char*fmt, ...))
{
- int creq, dhx, cipher;
+ int i, creq, dhx, cipher;
TlsConnection *c;
Bytes *epm;
Msg m;
@@ -1057,7 +1244,7 @@
c->ctl = ctl;
c->hand = hand;
c->trace = trace;
- c->cert = nil;
+ c->certs = nil;
c->sendp = c->buf;
c->version = ProtocolVersion;
@@ -1118,11 +1305,15 @@
if(!msgRecv(c, &m))
goto Err;
if(m.tag == HCertificate){
+fprint(2, "here! %d\n", m.u.certificate.ncert);
if(m.u.certificate.ncert < 1) {
tlsError(c, EIllegalParameter, "runt certificate");
goto Err;
}
- c->cert = makebytes(m.u.certificate.certs[0]->data, m.u.certificate.certs[0]->len);
+ c->ncerts = m.u.certificate.ncert;
+ c->certs = emalloc(c->ncerts * sizeof(Bytes*));
+ for(i = 0; i < c->ncerts; i++)
+ c->certs[i] = makebytes(m.u.certificate.certs[i]->data, m.u.certificate.certs[i]->len);
if(!msgRecv(c, &m))
goto Err;
} else if(psklen == 0) {
@@ -1133,7 +1324,7 @@
if(dhx){
char *err = verifyDHparams(c->sec,
m.u.serverKeyExchange.dh_parameters,
- c->cert,
+ c->certs[0],
m.u.serverKeyExchange.dh_signature,
c->version<TLS12Version ? 0x01 : m.u.serverKeyExchange.sigalg);
if(err != nil){
@@ -1179,8 +1370,8 @@
msgClear(&m);
if(!dhx){
- if(c->cert != nil){
- epm = tlsSecRSAc(c->sec, c->cert->data, c->cert->len);
+ if(c->certs != nil){
+ epm = tlsSecRSAc(c->sec, c->certs[0]->data, c->certs[0]->len);
if(epm == nil){
tlsError(c, EBadCertificate, "bad certificate: %r");
goto Err;
@@ -2100,11 +2291,12 @@
static void
tlsConnectionFree(TlsConnection *c)
{
+ int i;
+
if(c == nil)
return;
dh_finish(&c->sec->dh, nil);
-
mpfree(c->sec->ec.Q.x);
mpfree(c->sec->ec.Q.y);
mpfree(c->sec->ec.Q.d);
@@ -2112,12 +2304,58 @@
factotum_rsa_close(c->sec->rpc);
rsapubfree(c->sec->rsapub);
- freebytes(c->cert);
+ for(i = 0; i < c->ncerts; i++)
+ freebytes(c->certs[i]);
+ free(c->certs);
memset(c, 0, sizeof(*c));
free(c);
}
+static int
+validCert(char *host, PEMChain *pc)
+{
+ char *q, *t, buf[64];
+ PEMChain *e;
+ int n, fd, r;
+
+print("host: %s\n", host);
+ if(host == nil)
+ return 0;
+ if((fd = open("/mnt/pki/new", ORDWR)) == -1)
+ return 0;
+ q = quotestrdup(host);
+ fprint(fd, "verify host %s", q);
+ free(q);
+
+ t = "cert";
+ for(e = pc; e != nil; e = e->next){
+fprint(2, "%s der %d\n", t, e->pemlen);
+ if((r = fprint(fd, "%s der %d\n", t, e->pemlen)) == -1){
+fprint(2, "nope0[%d]: %r", r);
+ close(fd);
+ return 0;
+ }
+ if((write(fd, e->pem, e->pemlen)) != e->pemlen){
+fprint(2, "nope1: %r");
+ close(fd);
+ return 0;
+ }
+ t = "icert";
+ }
+ fprint(fd, "done\n");
+ if((n = pread(fd, buf, sizeof(buf)-1, 0)) == -1){
+ close(fd);
+ return 0;
+ }
+ buf[n] = 0;
+ close(fd);
+ if(strcmp(buf, "accept") != 0){
+ werrstr("cert validation failed: %s", buf);
+ return 0;
+ }
+ return 1;
+}
//================= cipher choices ========================
--- a/sys/src/libsec/port/x509.c
+++ b/sys/src/libsec/port/x509.c
@@ -128,7 +128,7 @@
static int is_octetstring(Elem* pe, Bytes** poctets);
static int is_oid(Elem* pe, Ints** poid);
static int is_string(Elem* pe, char** pstring);
-static int is_time(Elem* pe, char** ptime);
+static int parse_time(Elem* pe, vlong* ptime);
static int decode(uchar* a, int alen, Elem* pelem);
static int encode(Elem e, Bytes** pbytes);
static int oid_lookup(Ints* o, Ints** tab);
@@ -1277,15 +1277,24 @@
}
static int
-is_time(Elem* pe, char** ptime)
+parse_time(Elem* pe, vlong* ptime)
{
- if(pe->tag.class == Universal
- && (pe->tag.num == UTCTime || pe->tag.num == GeneralizedTime)
- && pe->val.tag == VString) {
- *ptime = pe->val.u.stringval;
- return 1;
+ char *e, *fmt;
+ Tm t;
+
+ if(pe->tag.class != Universal)
+ return 0;
+ if(pe->val.tag != VString)
+ return 0;
+ switch(pe->tag.num){
+ case UTCTime: fmt = "YYMMDDhhmmss?Z"; break;
+ case GeneralizedTime: fmt = "YYYYMMDDhhmmss?Z"; break;
+ default: return 0; break;
}
- return 0;
+ if(tmparse(&t, fmt, pe->val.u.stringval, nil, &e) == nil)
+ return 0;
+ *ptime = tmnorm(&t);
+ return 1;
}
@@ -1581,20 +1590,6 @@
* revocationDate UTCTime}
*/
-typedef struct CertX509 {
- int serial;
- char* issuer;
- char* validity_start;
- char* validity_end;
- char* subject;
- int publickey_alg;
- Bits* publickey;
- int signature_alg;
- Bits* signature;
- int curve;
- Bytes* ext;
-} CertX509;
-
/* Algorithm object-ids */
enum {
ALG_rsaEncryption,
@@ -1730,14 +1725,12 @@
static void appendaltnames(char *name, int nname, Bytes *ext, int req);
-static void
-freecert(CertX509* c)
+void
+X509free(CertX509* c)
{
if(c == nil)
return;
free(c->issuer);
- free(c->validity_start);
- free(c->validity_end);
free(c->subject);
freebits(c->publickey);
freebits(c->signature);
@@ -1791,7 +1784,7 @@
el = el->tl;
}
if(i > 0) {
- ans = (char*)emalloc(plen);
+ ans = emalloc(plen);
*ans = '\0';
while(--i >= 0) {
s = parts[i];
@@ -1833,154 +1826,6 @@
return oid_lookup(oid, namedcurves_oid_tab);
}
-static CertX509*
-decode_cert(uchar *buf, int len)
-{
- int ok = 0;
- int n;
- Elem ecert;
- Elem* ecertinfo;
- Elem* esigalg;
- Elem* esig;
- Elem* eserial;
- Elem* eissuer;
- Elem* evalidity;
- Elem* esubj;
- Elem* epubkey;
- Elist* el;
- Elist* elcert = nil;
- Elist* elcertinfo = nil;
- Elist* elvalidity = nil;
- Elist* elpubkey = nil;
- Bits* bits = nil;
- Bytes* b;
- Elem* e;
- CertX509* c = nil;
-
- if(decode(buf, len, &ecert) != ASN_OK)
- goto errret;
-
- c = (CertX509*)emalloc(sizeof(CertX509));
- c->serial = -1;
- c->issuer = nil;
- c->validity_start = nil;
- c->validity_end = nil;
- c->subject = nil;
- c->publickey_alg = -1;
- c->publickey = nil;
- c->signature_alg = -1;
- c->signature = nil;
- c->ext = nil;
-
- /* Certificate */
- if(!is_seq(&ecert, &elcert) || elistlen(elcert) !=3)
- goto errret;
- ecertinfo = &elcert->hd;
- el = elcert->tl;
- esigalg = &el->hd;
- c->signature_alg = parse_alg(esigalg);
- el = el->tl;
- esig = &el->hd;
-
- /* Certificate Info */
- if(!is_seq(ecertinfo, &elcertinfo))
- goto errret;
- n = elistlen(elcertinfo);
- if(n < 6)
- goto errret;
- eserial =&elcertinfo->hd;
- el = elcertinfo->tl;
- /* check for optional version, marked by explicit context tag 0 */
- if(eserial->tag.class == Context && eserial->tag.num == 0) {
- eserial = &el->hd;
- if(n < 7)
- goto errret;
- el = el->tl;
- }
-
- if(parse_alg(&el->hd) != c->signature_alg)
- goto errret;
- el = el->tl;
- eissuer = &el->hd;
- el = el->tl;
- evalidity = &el->hd;
- el = el->tl;
- esubj = &el->hd;
- el = el->tl;
- epubkey = &el->hd;
- if(el->tl != nil
- && el->tl->hd.tag.class == Context
- && el->tl->hd.tag.num == 3
- && el->tl->hd.val.tag == VOctets){
- c->ext = el->tl->hd.val.u.octetsval;
- el->tl->hd.val.u.octetsval = nil; /* transfer ownership */
- }
- if(!is_int(eserial, &c->serial)) {
- if(!is_bigint(eserial, &b))
- goto errret;
- c->serial = -1; /* else we have to change cert struct */
- }
- c->issuer = parse_name(eissuer);
- if(c->issuer == nil)
- goto errret;
- /* Validity */
- if(!is_seq(evalidity, &elvalidity))
- goto errret;
- if(elistlen(elvalidity) != 2)
- goto errret;
- e = &elvalidity->hd;
- if(!is_time(e, &c->validity_start))
- goto errret;
- e->val.u.stringval = nil; /* string ownership transfer */
- e = &elvalidity->tl->hd;
- if(!is_time(e, &c->validity_end))
- goto errret;
- e->val.u.stringval = nil; /* string ownership transfer */
-
- /* resume CertificateInfo */
- c->subject = parse_name(esubj);
- if(c->subject == nil)
- goto errret;
-
- /* SubjectPublicKeyInfo */
- if(!is_seq(epubkey, &elpubkey))
- goto errret;
- if(elistlen(elpubkey) != 2)
- goto errret;
-
- c->publickey_alg = parse_alg(&elpubkey->hd);
- if(c->publickey_alg < 0)
- goto errret;
- c->curve = -1;
- if(c->publickey_alg == ALG_ecPublicKey){
- c->curve = parse_curve(&elpubkey->hd);
- if(c->curve < 0)
- goto errret;
- }
- elpubkey = elpubkey->tl;
- if(!is_bitstring(&elpubkey->hd, &bits))
- goto errret;
- elpubkey->hd.val.u.bitstringval = nil; /* transfer ownership */
- c->publickey = bits;
-
- /*resume Certificate */
- if(c->signature_alg < 0)
- goto errret;
- if(!is_bitstring(esig, &bits))
- goto errret;
- esig->val.u.bitstringval = nil; /* transfer ownership */
- c->signature = bits;
- ok = 1;
-
-errret:
- freevalfields(&ecert.val); /* recurses through lists, too */
- if(!ok){
- freecert(c);
- c = nil;
- }
- return c;
-}
-
/*
* RSAPublickKey ::= SEQUENCE {
* modulus INTEGER,
@@ -2187,6 +2032,156 @@
static char Ebadsig[] = "bad signature";
+CertX509*
+X509decode(uchar *buf, int len)
+{
+ int ok = 0;
+ int n;
+ Elem ecert;
+ Elem* ecertinfo;
+ Elem* esigalg;
+ Elem* esig;
+ Elem* eserial;
+ Elem* eissuer;
+ Elem* evalidity;
+ Elem* esubj;
+ Elem* epubkey;
+ Elist* el;
+ Elist* elcert = nil;
+ Elist* elcertinfo = nil;
+ Elist* elvalidity = nil;
+ Elist* elpubkey = nil;
+ Bits* bits = nil;
+ Bytes* b;
+ Elem* e;
+ CertX509* c = nil;
+
+ if(decode(buf, len, &ecert) != ASN_OK)
+ goto errret;
+
+ c = (CertX509*)emalloc(sizeof(CertX509));
+ c->serial = -1;
+ c->issuer = nil;
+ c->validity_start = -1;
+ c->validity_end = -1;
+ c->subject = nil;
+ c->altsubject = nil;
+ c->publickey_alg = -1;
+ c->publickey = nil;
+ c->signature_alg = -1;
+ c->signature = nil;
+ c->ext = nil;
+
+ /* Certificate */
+ if(!is_seq(&ecert, &elcert) || elistlen(elcert) !=3)
+ goto errret;
+ ecertinfo = &elcert->hd;
+ el = elcert->tl;
+ esigalg = &el->hd;
+ c->signature_alg = parse_alg(esigalg);
+ el = el->tl;
+ esig = &el->hd;
+
+ /* Certificate Info */
+ if(!is_seq(ecertinfo, &elcertinfo))
+ goto errret;
+ n = elistlen(elcertinfo);
+ if(n < 6)
+ goto errret;
+ eserial =&elcertinfo->hd;
+ el = elcertinfo->tl;
+ /* check for optional version, marked by explicit context tag 0 */
+ if(eserial->tag.class == Context && eserial->tag.num == 0) {
+ eserial = &el->hd;
+ if(n < 7)
+ goto errret;
+ el = el->tl;
+ }
+
+ if(parse_alg(&el->hd) != c->signature_alg)
+ goto errret;
+ el = el->tl;
+ eissuer = &el->hd;
+ el = el->tl;
+ evalidity = &el->hd;
+ el = el->tl;
+ esubj = &el->hd;
+ el = el->tl;
+ epubkey = &el->hd;
+ if(el->tl != nil
+ && el->tl->hd.tag.class == Context
+ && el->tl->hd.tag.num == 3
+ && el->tl->hd.val.tag == VOctets){
+ c->ext = el->tl->hd.val.u.octetsval;
+ el->tl->hd.val.u.octetsval = nil; /* transfer ownership */
+ }
+ if(!is_int(eserial, &c->serial)) {
+ if(!is_bigint(eserial, &b))
+ goto errret;
+ c->serial = -1; /* else we have to change cert struct */
+ }
+ c->issuer = parse_name(eissuer);
+ if(c->issuer == nil)
+ goto errret;
+ /* Validity */
+ if(!is_seq(evalidity, &elvalidity))
+ goto errret;
+ if(elistlen(elvalidity) != 2)
+ goto errret;
+ e = &elvalidity->hd;
+ if(!parse_time(e, &c->validity_start))
+ goto errret;
+ e = &elvalidity->tl->hd;
+ if(!parse_time(e, &c->validity_end))
+ goto errret;
+
+ /* resume CertificateInfo */
+ c->subject = parse_name(esubj);
+ if(c->subject == nil)
+ goto errret;
+
+ /* SubjectPublicKeyInfo */
+ if(!is_seq(epubkey, &elpubkey))
+ goto errret;
+ if(elistlen(elpubkey) != 2)
+ goto errret;
+
+ c->publickey_alg = parse_alg(&elpubkey->hd);
+ if(c->publickey_alg < 0)
+ goto errret;
+ c->curve = -1;
+ if(c->publickey_alg == ALG_ecPublicKey){
+ c->curve = parse_curve(&elpubkey->hd);
+ if(c->curve < 0)
+ goto errret;
+ }
+ elpubkey = elpubkey->tl;
+ if(!is_bitstring(&elpubkey->hd, &bits))
+ goto errret;
+ elpubkey->hd.val.u.bitstringval = nil; /* transfer ownership */
+ c->publickey = bits;
+
+ /*resume Certificate */
+ if(c->signature_alg < 0)
+ goto errret;
+ if(!is_bitstring(esig, &bits))
+ goto errret;
+ esig->val.u.bitstringval = nil; /* transfer ownership */
+ c->signature = bits;
+ c->digestlen = digest_certinfo(buf, len, digestalg[c->signature_alg], c->digest);
+ if(c->digestlen < 0)
+ goto errret;
+ ok = 1;
+
+errret:
+ freevalfields(&ecert.val); /* recurses through lists, too */
+ if(!ok){
+ X509free(c);
+ c = nil;
+ }
+ return c;
+}
+
char*
X509rsaverifydigest(uchar *sig, int siglen, uchar *edigest, int edigestlen, RSApub *pk)
{
@@ -2288,8 +2283,9 @@
{
CertX509 *c;
ECpub *pub;
+ Bits *pk;
- c = decode_cert(cert, ncert);
+ c = X509decode(cert, ncert);
if(c == nil)
return nil;
copysubject(name, nname, c->subject);
@@ -2297,11 +2293,12 @@
pub = nil;
if(c->publickey_alg == ALG_ecPublicKey){
ecdominit(dom, namedcurves[c->curve]);
- pub = ecdecodepub(dom, c->publickey->data, c->publickey->len);
+ pk = c->publickey;
+ pub = ecdecodepub(dom, pk->data, pk->len);
if(pub == nil)
ecdomfree(dom);
}
- freecert(c);
+ X509free(c);
return pub;
}
@@ -2309,20 +2306,22 @@
X509ecdsaverify(uchar *cert, int ncert, ECdomain *dom, ECpub *pk)
{
char *e;
+ Bits *sig;
CertX509 *c;
int digestlen;
uchar digest[MAXdlen];
- c = decode_cert(cert, ncert);
+ c = X509decode(cert, ncert);
if(c == nil)
return "cannot decode cert";
digestlen = digest_certinfo(cert, ncert, digestalg[c->signature_alg], digest);
if(digestlen <= 0){
- freecert(c);
+ X509free(c);
return "cannot decode certinfo";
}
- e = X509ecdsaverifydigest(c->signature->data, c->signature->len, digest, digestlen, dom, pk);
- freecert(c);
+ sig = c->signature;
+ e = X509ecdsaverifydigest(sig->data, sig->len, digest, digestlen, dom, pk);
+ X509free(c);
return e;
}
@@ -2331,40 +2330,71 @@
{
CertX509 *c;
RSApub *pub;
+ Bits *pk;
- c = decode_cert(cert, ncert);
+ c = X509decode(cert, ncert);
if(c == nil)
return nil;
copysubject(name, nname, c->subject);
appendaltnames(name, nname, c->ext, 0);
pub = nil;
+ pk = c->publickey;
if(c->publickey_alg == ALG_rsaEncryption)
- pub = asn1toRSApub(c->publickey->data, c->publickey->len);
- freecert(c);
+ pub = asn1toRSApub(pk->data, pk->len);
+ X509free(c);
return pub;
}
-char*
+char*
X509rsaverify(uchar *cert, int ncert, RSApub *pk)
{
char *e;
+ Bits *sig;
CertX509 *c;
int digestlen;
uchar digest[MAXdlen];
- c = decode_cert(cert, ncert);
+ c = X509decode(cert, ncert);
if(c == nil)
return "cannot decode cert";
digestlen = digest_certinfo(cert, ncert, digestalg[c->signature_alg], digest);
if(digestlen <= 0){
- freecert(c);
+ X509free(c);
return "cannot decode certinfo";
}
- e = X509rsaverifydigest(c->signature->data, c->signature->len, digest, digestlen, pk);
- freecert(c);
+ sig = c->signature;
+ e = X509rsaverifydigest(sig->data, sig->len, digest, digestlen, pk);
+ X509free(c);
return e;
}
+char*
+X509verify(CertX509 *crt, CertX509 *vrf)
+{
+ RSApub *rsapub;
+ ECpub *ecpub;
+ ECdomain ecdom;
+ Bits *pk, *sig;
+ char *e;
+
+ e = "unknown algorithm";
+ pk = vrf->publickey;
+ sig = crt->signature;
+ switch(vrf->publickey_alg){
+ case ALG_rsaEncryption:
+ rsapub = asn1toRSApub(pk->data, pk->len);
+ e = X509rsaverifydigest(sig->data, sig->len, crt->digest, crt->digestlen, rsapub);
+ break;
+ case ALG_ecPublicKey:
+ ecdominit(&ecdom, namedcurves[vrf->curve]);
+ ecpub = ecdecodepub(&ecdom, pk->data, pk->len);
+ e = X509ecdsaverifydigest(sig->data, sig->len, crt->digest, crt->digestlen, &ecdom, ecpub);
+ ecdomfree(&ecdom);
+ break;
+ }
+ return e;
+}
+
/* ------- Elem constructors ---------- */
static Elem
Null(void)
@@ -3125,14 +3155,16 @@
X509digestSPKI(uchar *cert, int ncert, DigestState* (*fun)(uchar*, ulong, uchar*, DigestState*), uchar *digest)
{
CertX509 *c;
+ Bits *pk;
- c = decode_cert(cert, ncert);
+ c = X509decode(cert, ncert);
if(c == nil){
werrstr("cannot decode cert");
return -1;
}
- digestSPKI(c->publickey_alg, c->publickey->data, c->publickey->len, fun, digest);
- freecert(c);
+ pk = c->publickey;
+ digestSPKI(c->publickey_alg, pk->data, pk->len, fun, digest);
+ X509free(c);
return 0;
}
@@ -3227,60 +3259,55 @@
}
void
-X509dump(uchar *cert, int ncert)
+X509dump(int fd, uchar *cert, int ncert)
{
char *e;
+ Bits *pk, *sig;
CertX509 *c;
RSApub *rsapub;
ECpub *ecpub;
ECdomain ecdom;
- int digestlen;
uchar digest[MAXdlen];
- print("begin X509dump\n");
- c = decode_cert(cert, ncert);
+ fprint(fd, "begin X509dump\n");
+ c = X509decode(cert, ncert);
if(c == nil){
- print("cannot decode cert\n");
+ fprint(fd, "cannot decode cert\n");
return;
}
- digestlen = digest_certinfo(cert, ncert, digestalg[c->signature_alg], digest);
- if(digestlen <= 0){
- freecert(c);
- print("cannot decode certinfo\n");
- return;
- }
+ pk = c->publickey;
+ sig = c->signature;
+ fprint(fd, "serial %d\n", c->serial);
+ fprint(fd, "issuer %s\n", c->issuer);
+ fprint(fd, "validity %lld %lld\n", c->validity_start, c->validity_end);
+ fprint(fd, "subject %s\n", c->subject);
+ fprint(fd, "sigalg=%d digest=%.*H\n", c->signature_alg, c->digestlen, c->digest);
+ fprint(fd, "publickey_alg=%d pubkey[%d] %.*H\n", c->publickey_alg, pk->len,
+ pk->len, pk->data);
- 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);
- print("sigalg=%d digest=%.*H\n", c->signature_alg, digestlen, digest);
- print("publickey_alg=%d pubkey[%d] %.*H\n", c->publickey_alg, c->publickey->len,
- c->publickey->len, c->publickey->data);
-
switch(c->publickey_alg){
case ALG_rsaEncryption:
- rsapub = asn1toRSApub(c->publickey->data, c->publickey->len);
+ rsapub = asn1toRSApub(pk->data, pk->len);
if(rsapub != nil){
- print("rsa pubkey e=%B n(%d)=%B\n", rsapub->ek, mpsignif(rsapub->n), rsapub->n);
- e = X509rsaverifydigest(c->signature->data, c->signature->len,
- digest, digestlen, rsapub);
+ fprint(fd, "rsa pubkey e=%B n(%d)=%B\n", rsapub->ek, mpsignif(rsapub->n), rsapub->n);
+ e = X509rsaverifydigest(sig->data, sig->len,
+ c->digest, c->digestlen, rsapub);
if(e==nil)
e = "nil (meaning ok)";
- print("self-signed X509rsaverifydigest returns: %s\n", e);
+ fprint(fd, "self-signed X509rsaverifydigest returns: %s\n", e);
rsapubfree(rsapub);
}
break;
case ALG_ecPublicKey:
ecdominit(&ecdom, namedcurves[c->curve]);
- ecpub = ecdecodepub(&ecdom, c->publickey->data, c->publickey->len);
+ ecpub = ecdecodepub(&ecdom, pk->data, pk->len);
if(ecpub != nil){
- e = X509ecdsaverifydigest(c->signature->data, c->signature->len,
- digest, digestlen, &ecdom, ecpub);
+ e = X509ecdsaverifydigest(sig->data, sig->len,
+ c->digest, c->digestlen, &ecdom, ecpub);
if(e==nil)
e = "nil (meaning ok)";
- print("self-signed X509ecdsaverifydigest returns: %s\n", e);
+ fprint(fd, "self-signed X509ecdsaverifydigest returns: %s\n", e);
ecpubfree(ecpub);
}
ecdomfree(&ecdom);
@@ -3287,15 +3314,15 @@
break;
}
- digestSPKI(c->publickey_alg, c->publickey->data, c->publickey->len, sha2_256, digest);
- print("publickey_thumbprint sha256=%.*[\n", SHA2_256dlen, digest);
+ digestSPKI(c->publickey_alg, pk->data, pk->len, sha2_256, c->digest);
+ fprint(fd, "publickey_thumbprint sha256=%.*[\n", SHA2_256dlen, c->digest);
sha2_256(cert, ncert, digest, nil);
- print("cert_thumbprint sha256=%.*[\n", SHA2_256dlen, digest);
+ fprint(fd, "cert_thumbprint sha256=%.*[\n", SHA2_256dlen, digest);
sha1(cert, ncert, digest, nil);
- print("cert_thumbprint sha1=%.*H\n", SHA1dlen, digest);
+ fprint(fd, "cert_thumbprint sha1=%.*H\n", SHA1dlen, digest);
- freecert(c);
- print("end X509dump\n");
+ X509free(c);
+ fprint(fd, "end X509dump\n");
}