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.
This commit is contained in:
parent
ada54defbc
commit
9f50ee06f3
2 changed files with 60 additions and 15 deletions
|
@ -130,6 +130,7 @@ typedef struct Msg{
|
||||||
} certificate;
|
} certificate;
|
||||||
struct {
|
struct {
|
||||||
Bytes *types;
|
Bytes *types;
|
||||||
|
Ints *sigalgs;
|
||||||
int nca;
|
int nca;
|
||||||
Bytes **cas;
|
Bytes **cas;
|
||||||
} certificateRequest;
|
} certificateRequest;
|
||||||
|
@ -146,6 +147,7 @@ typedef struct Msg{
|
||||||
int curve;
|
int curve;
|
||||||
} serverKeyExchange;
|
} serverKeyExchange;
|
||||||
struct {
|
struct {
|
||||||
|
int sigalg;
|
||||||
Bytes *signature;
|
Bytes *signature;
|
||||||
} certificateVerify;
|
} certificateVerify;
|
||||||
Finished finished;
|
Finished finished;
|
||||||
|
@ -387,6 +389,7 @@ static void freeints(Ints* b);
|
||||||
/* x509.c */
|
/* x509.c */
|
||||||
extern mpint* pkcs1padbuf(uchar *buf, int len, mpint *modulus);
|
extern mpint* pkcs1padbuf(uchar *buf, int len, mpint *modulus);
|
||||||
extern int pkcs1decryptsignature(uchar *sig, int siglen, RSApub *pk, uchar **pbuf);
|
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 ========================
|
//================= client/server ========================
|
||||||
|
|
||||||
|
@ -1024,7 +1027,6 @@ tlsClient2(int ctl, int hand, uchar *csid, int ncsid, uchar *cert, int certlen,
|
||||||
uchar kd[MaxKeyData];
|
uchar kd[MaxKeyData];
|
||||||
char *secrets;
|
char *secrets;
|
||||||
int creq, dhx, rv, cipher;
|
int creq, dhx, rv, cipher;
|
||||||
mpint *signedMP, *paddedHashes;
|
|
||||||
Bytes *epm;
|
Bytes *epm;
|
||||||
|
|
||||||
if(!initCiphers())
|
if(!initCiphers())
|
||||||
|
@ -1033,10 +1035,6 @@ tlsClient2(int ctl, int hand, uchar *csid, int ncsid, uchar *cert, int certlen,
|
||||||
c = emalloc(sizeof(TlsConnection));
|
c = emalloc(sizeof(TlsConnection));
|
||||||
c->version = ProtocolVersion;
|
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->ctl = ctl;
|
||||||
c->hand = hand;
|
c->hand = hand;
|
||||||
c->trace = trace;
|
c->trace = trace;
|
||||||
|
@ -1201,14 +1199,10 @@ tlsClient2(int ctl, int hand, uchar *csid, int ncsid, uchar *cert, int certlen,
|
||||||
|
|
||||||
/* certificate verify */
|
/* certificate verify */
|
||||||
if(creq && cert != nil && certlen > 0) {
|
if(creq && cert != nil && certlen > 0) {
|
||||||
uchar hshashes[MD5dlen+SHA1dlen]; /* content of signature */
|
mpint *signedMP, *paddedHashes;
|
||||||
HandshakeHash hsave;
|
HandshakeHash hsave;
|
||||||
|
uchar buf[512];
|
||||||
/* save the state for the Finish message */
|
int buflen;
|
||||||
hsave = c->handhash;
|
|
||||||
md5(nil, 0, hshashes, &c->handhash.md5);
|
|
||||||
sha1(nil, 0, hshashes+MD5dlen, &c->handhash.sha1);
|
|
||||||
c->handhash = hsave;
|
|
||||||
|
|
||||||
c->sec->rpc = factotum_rsa_open(cert, certlen);
|
c->sec->rpc = factotum_rsa_open(cert, certlen);
|
||||||
if(c->sec->rpc == nil){
|
if(c->sec->rpc == nil){
|
||||||
|
@ -1221,7 +1215,22 @@ tlsClient2(int ctl, int hand, uchar *csid, int ncsid, uchar *cert, int certlen,
|
||||||
goto Err;
|
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);
|
signedMP = factotum_rsa_decrypt(c->sec->rpc, paddedHashes);
|
||||||
if(signedMP == nil){
|
if(signedMP == nil){
|
||||||
tlsError(c, EHandshakeFailure, "factotum_rsa_decrypt: %r");
|
tlsError(c, EHandshakeFailure, "factotum_rsa_decrypt: %r");
|
||||||
|
@ -1410,6 +1419,10 @@ msgSend(TlsConnection *c, Msg *m, int act)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case HCertificateVerify:
|
case HCertificateVerify:
|
||||||
|
if(m->u.certificateVerify.sigalg != 0){
|
||||||
|
put16(p, m->u.certificateVerify.sigalg);
|
||||||
|
p += 2;
|
||||||
|
}
|
||||||
put16(p, m->u.certificateVerify.signature->len);
|
put16(p, m->u.certificateVerify.signature->len);
|
||||||
p += 2;
|
p += 2;
|
||||||
memmove(p, m->u.certificateVerify.signature->data, m->u.certificateVerify.signature->len);
|
memmove(p, m->u.certificateVerify.signature->data, m->u.certificateVerify.signature->len);
|
||||||
|
@ -1684,14 +1697,16 @@ msgRecv(TlsConnection *c, Msg *m)
|
||||||
p += nn;
|
p += nn;
|
||||||
n -= nn;
|
n -= nn;
|
||||||
if(c->version >= TLS12Version){
|
if(c->version >= TLS12Version){
|
||||||
/* skip supported_signature_algorithms */
|
|
||||||
if(n < 2)
|
if(n < 2)
|
||||||
goto Short;
|
goto Short;
|
||||||
nn = get16(p);
|
nn = get16(p);
|
||||||
p += 2;
|
p += 2;
|
||||||
n -= 2;
|
n -= 2;
|
||||||
if(nn > n)
|
if(nn & 1)
|
||||||
goto Short;
|
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;
|
p += nn;
|
||||||
n -= nn;
|
n -= nn;
|
||||||
|
|
||||||
|
@ -1861,6 +1876,7 @@ msgClear(Msg *m)
|
||||||
break;
|
break;
|
||||||
case HCertificateRequest:
|
case HCertificateRequest:
|
||||||
freebytes(m->u.certificateRequest.types);
|
freebytes(m->u.certificateRequest.types);
|
||||||
|
freeints(m->u.certificateRequest.sigalgs);
|
||||||
for(i=0; i<m->u.certificateRequest.nca; i++)
|
for(i=0; i<m->u.certificateRequest.nca; i++)
|
||||||
freebytes(m->u.certificateRequest.cas[i]);
|
freebytes(m->u.certificateRequest.cas[i]);
|
||||||
free(m->u.certificateRequest.cas);
|
free(m->u.certificateRequest.cas);
|
||||||
|
@ -1969,12 +1985,16 @@ msgPrint(char *buf, int n, Msg *m)
|
||||||
case HCertificateRequest:
|
case HCertificateRequest:
|
||||||
bs = seprint(bs, be, "CertificateRequest\n");
|
bs = seprint(bs, be, "CertificateRequest\n");
|
||||||
bs = bytesPrint(bs, be, "\ttypes: ", m->u.certificateRequest.types, "\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");
|
bs = seprint(bs, be, "\tcertificateauthorities\n");
|
||||||
for(i=0; i<m->u.certificateRequest.nca; i++)
|
for(i=0; i<m->u.certificateRequest.nca; i++)
|
||||||
bs = bytesPrint(bs, be, "\t\t", m->u.certificateRequest.cas[i], "\n");
|
bs = bytesPrint(bs, be, "\t\t", m->u.certificateRequest.cas[i], "\n");
|
||||||
break;
|
break;
|
||||||
case HCertificateVerify:
|
case HCertificateVerify:
|
||||||
bs = seprint(bs, be, "HCertificateVerify\n");
|
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");
|
bs = bytesPrint(bs, be, "\tsignature: ", m->u.certificateVerify.signature,"\n");
|
||||||
break;
|
break;
|
||||||
case HServerHelloDone:
|
case HServerHelloDone:
|
||||||
|
|
|
@ -2496,6 +2496,31 @@ mkDN(char *dn)
|
||||||
return mkseq(el);
|
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*
|
uchar*
|
||||||
X509gen(RSApriv *priv, char *subj, ulong valid[2], int *certlen)
|
X509gen(RSApriv *priv, char *subj, ulong valid[2], int *certlen)
|
||||||
|
|
Loading…
Reference in a new issue