summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2015-09-23 16:57:25 +0200
committercinap_lenrek <cinap_lenrek@felloff.net>2015-09-23 16:57:25 +0200
commit9f50ee06f3a78af3767ec061f4647b5446c8619e (patch)
tree1532d6fc3cd4cf5977a84a78dcbb3835ad7a1dd6
parentada54defbcb037f8858b475f90ef215b7d1b44a6 (diff)
downloadplan9front-9f50ee06f3a78af3767ec061f4647b5446c8619e.tar.xz
libsec: implement client certificate authentication for tls1.2
we used to negotiate tls1.1 for client cert authentication because the signature generation was not implemented for tls1.2. this is now fixed and tls1.2 can be negotiated with client certs.
-rw-r--r--sys/src/libsec/port/tlshand.c50
-rw-r--r--sys/src/libsec/port/x509.c25
2 files changed, 60 insertions, 15 deletions
diff --git a/sys/src/libsec/port/tlshand.c b/sys/src/libsec/port/tlshand.c
index 4a2e4f481..bc6506704 100644
--- a/sys/src/libsec/port/tlshand.c
+++ b/sys/src/libsec/port/tlshand.c
@@ -130,6 +130,7 @@ typedef struct Msg{
} certificate;
struct {
Bytes *types;
+ Ints *sigalgs;
int nca;
Bytes **cas;
} certificateRequest;
@@ -146,6 +147,7 @@ typedef struct Msg{
int curve;
} serverKeyExchange;
struct {
+ int sigalg;
Bytes *signature;
} certificateVerify;
Finished finished;
@@ -387,6 +389,7 @@ static void freeints(Ints* b);
/* x509.c */
extern mpint* pkcs1padbuf(uchar *buf, int len, mpint *modulus);
extern int pkcs1decryptsignature(uchar *sig, int siglen, RSApub *pk, uchar **pbuf);
+extern int X509encodesignature_sha256(uchar digest[SHA2_256dlen], uchar *buf, int len);
//================= client/server ========================
@@ -1024,7 +1027,6 @@ tlsClient2(int ctl, int hand, uchar *csid, int ncsid, uchar *cert, int certlen,
uchar kd[MaxKeyData];
char *secrets;
int creq, dhx, rv, cipher;
- mpint *signedMP, *paddedHashes;
Bytes *epm;
if(!initCiphers())
@@ -1033,10 +1035,6 @@ tlsClient2(int ctl, int hand, uchar *csid, int ncsid, uchar *cert, int certlen,
c = emalloc(sizeof(TlsConnection));
c->version = ProtocolVersion;
- // client certificate signature not implemented for TLS1.2
- if(cert != nil && certlen > 0 && c->version >= TLS12Version)
- c->version = TLS11Version;
-
c->ctl = ctl;
c->hand = hand;
c->trace = trace;
@@ -1201,14 +1199,10 @@ tlsClient2(int ctl, int hand, uchar *csid, int ncsid, uchar *cert, int certlen,
/* certificate verify */
if(creq && cert != nil && certlen > 0) {
- uchar hshashes[MD5dlen+SHA1dlen]; /* content of signature */
+ mpint *signedMP, *paddedHashes;
HandshakeHash hsave;
-
- /* save the state for the Finish message */
- hsave = c->handhash;
- md5(nil, 0, hshashes, &c->handhash.md5);
- sha1(nil, 0, hshashes+MD5dlen, &c->handhash.sha1);
- c->handhash = hsave;
+ uchar buf[512];
+ int buflen;
c->sec->rpc = factotum_rsa_open(cert, certlen);
if(c->sec->rpc == nil){
@@ -1221,7 +1215,22 @@ tlsClient2(int ctl, int hand, uchar *csid, int ncsid, uchar *cert, int certlen,
goto Err;
}
- paddedHashes = pkcs1padbuf(hshashes, MD5dlen+SHA1dlen, c->sec->rsapub->n);
+ /* save the state for the Finish message */
+ hsave = c->handhash;
+ if(c->version >= TLS12Version){
+ uchar digest[SHA2_256dlen];
+
+ m.u.certificateVerify.sigalg = 0x0401; /* RSA SHA256 */
+ sha2_256(nil, 0, digest, &c->handhash.sha2_256);
+ buflen = X509encodesignature_sha256(digest, buf, sizeof(buf));
+ } else {
+ md5(nil, 0, buf, &c->handhash.md5);
+ sha1(nil, 0, buf+MD5dlen, &c->handhash.sha1);
+ buflen = MD5dlen+SHA1dlen;
+ }
+ c->handhash = hsave;
+
+ paddedHashes = pkcs1padbuf(buf, buflen, c->sec->rsapub->n);
signedMP = factotum_rsa_decrypt(c->sec->rpc, paddedHashes);
if(signedMP == nil){
tlsError(c, EHandshakeFailure, "factotum_rsa_decrypt: %r");
@@ -1410,6 +1419,10 @@ msgSend(TlsConnection *c, Msg *m, int act)
}
break;
case HCertificateVerify:
+ if(m->u.certificateVerify.sigalg != 0){
+ put16(p, m->u.certificateVerify.sigalg);
+ p += 2;
+ }
put16(p, m->u.certificateVerify.signature->len);
p += 2;
memmove(p, m->u.certificateVerify.signature->data, m->u.certificateVerify.signature->len);
@@ -1684,14 +1697,16 @@ msgRecv(TlsConnection *c, Msg *m)
p += nn;
n -= nn;
if(c->version >= TLS12Version){
- /* skip supported_signature_algorithms */
if(n < 2)
goto Short;
nn = get16(p);
p += 2;
n -= 2;
- if(nn > n)
+ if(nn & 1)
goto Short;
+ m->u.certificateRequest.sigalgs = newints(nn>>1);
+ for(i = 0; i < nn; i += 2)
+ m->u.certificateRequest.sigalgs->data[i >> 1] = get16(&p[i]);
p += nn;
n -= nn;
@@ -1861,6 +1876,7 @@ msgClear(Msg *m)
break;
case HCertificateRequest:
freebytes(m->u.certificateRequest.types);
+ freeints(m->u.certificateRequest.sigalgs);
for(i=0; i<m->u.certificateRequest.nca; i++)
freebytes(m->u.certificateRequest.cas[i]);
free(m->u.certificateRequest.cas);
@@ -1969,12 +1985,16 @@ msgPrint(char *buf, int n, Msg *m)
case HCertificateRequest:
bs = seprint(bs, be, "CertificateRequest\n");
bs = bytesPrint(bs, be, "\ttypes: ", m->u.certificateRequest.types, "\n");
+ if(m->u.certificateRequest.sigalgs != nil)
+ bs = intsPrint(bs, be, "\tsigalgs: ", m->u.certificateRequest.sigalgs, "\n");
bs = seprint(bs, be, "\tcertificateauthorities\n");
for(i=0; i<m->u.certificateRequest.nca; i++)
bs = bytesPrint(bs, be, "\t\t", m->u.certificateRequest.cas[i], "\n");
break;
case HCertificateVerify:
bs = seprint(bs, be, "HCertificateVerify\n");
+ if(m->u.certificateVerify.sigalg != 0)
+ bs = seprint(bs, be, "\tsigalg: %.4x\n", m->u.certificateVerify.sigalg);
bs = bytesPrint(bs, be, "\tsignature: ", m->u.certificateVerify.signature,"\n");
break;
case HServerHelloDone:
diff --git a/sys/src/libsec/port/x509.c b/sys/src/libsec/port/x509.c
index b70ed2689..f6a396474 100644
--- a/sys/src/libsec/port/x509.c
+++ b/sys/src/libsec/port/x509.c
@@ -2496,6 +2496,31 @@ mkDN(char *dn)
return mkseq(el);
}
+int
+X509encodesignature_sha256(uchar digest[SHA2_256dlen], uchar *buf, int len)
+{
+ Bytes *sigbytes;
+ Elem sig;
+ int err;
+
+ sig = mkseq(
+ mkel(mkalg(ALG_sha256),
+ mkel(mkoctet(digest, SHA2_256dlen),
+ nil)));
+ err = encode(sig, &sigbytes);
+ freevalfields(&sig.val);
+ if(err != ASN_OK)
+ return -1;
+ if(len < sigbytes->len){
+ freebytes(sigbytes);
+ return -1;
+ }
+ len = sigbytes->len;
+ memmove(buf, sigbytes->data, len);
+ freebytes(sigbytes);
+
+ return len;
+}
uchar*
X509gen(RSApriv *priv, char *subj, ulong valid[2], int *certlen)