📄 tlshand.c
字号:
goto Err; } m.tag = HFinished; m.u.finished = c->finished; if(!msgSend(c, &m, AFlush)) goto Err; msgClear(&m); if(trace) trace("tls finished\n"); if(fprint(c->ctl, "opened") < 0) goto Err; tlsSecOk(c->sec); return c;Err: msgClear(&m); tlsConnectionFree(c); return 0;}static TlsConnection *tlsClient2(int ctl, int hand, uchar *csid, int ncsid, int (*trace)(char*fmt, ...)){ TlsConnection *c; Msg m; uchar kd[MaxKeyData], *epm; char *secrets; int creq, nepm, rv; if(!initCiphers()) return nil; epm = nil; c = emalloc(sizeof(TlsConnection)); c->version = ProtocolVersion; c->ctl = ctl; c->hand = hand; c->trace = trace; c->isClient = 1; c->clientVersion = c->version; c->sec = tlsSecInitc(c->clientVersion, c->crandom); if(c->sec == nil) goto Err; /* client hello */ memset(&m, 0, sizeof(m)); m.tag = HClientHello; m.u.clientHello.version = c->clientVersion; memmove(m.u.clientHello.random, c->crandom, RandomSize); m.u.clientHello.sid = makebytes(csid, ncsid); m.u.clientHello.ciphers = makeciphers(); m.u.clientHello.compressors = makebytes(compressors,sizeof(compressors)); if(!msgSend(c, &m, AFlush)) goto Err; msgClear(&m); /* server hello */ if(!msgRecv(c, &m)) goto Err; if(m.tag != HServerHello) { tlsError(c, EUnexpectedMessage, "expected a server hello"); goto Err; } if(setVersion(c, m.u.serverHello.version) < 0) { tlsError(c, EIllegalParameter, "incompatible version %r"); goto Err; } memmove(c->srandom, m.u.serverHello.random, RandomSize); c->sid = makebytes(m.u.serverHello.sid->data, m.u.serverHello.sid->len); if(c->sid->len != 0 && c->sid->len != SidSize) { tlsError(c, EIllegalParameter, "invalid server session identifier"); goto Err; } if(!setAlgs(c, m.u.serverHello.cipher)) { tlsError(c, EIllegalParameter, "invalid cipher suite"); goto Err; } if(m.u.serverHello.compressor != CompressionNull) { tlsError(c, EIllegalParameter, "invalid compression"); goto Err; } msgClear(&m); /* certificate */ if(!msgRecv(c, &m) || m.tag != HCertificate) { tlsError(c, EUnexpectedMessage, "expected a certificate"); goto Err; } 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); msgClear(&m); /* server key exchange (optional) */ if(!msgRecv(c, &m)) goto Err; if(m.tag == HServerKeyExchange) { tlsError(c, EUnexpectedMessage, "got an server key exchange"); goto Err; // If implementing this later, watch out for rollback attack // described in Wagner Schneier 1996, section 4.4. } /* certificate request (optional) */ creq = 0; if(m.tag == HCertificateRequest) { creq = 1; msgClear(&m); if(!msgRecv(c, &m)) goto Err; } if(m.tag != HServerHelloDone) { tlsError(c, EUnexpectedMessage, "expected a server hello done"); goto Err; } msgClear(&m); if(tlsSecSecretc(c->sec, c->sid->data, c->sid->len, c->srandom, c->cert->data, c->cert->len, c->version, &epm, &nepm, kd, c->nsecret) < 0){ tlsError(c, EBadCertificate, "invalid x509/rsa certificate"); goto Err; } secrets = (char*)emalloc(2*c->nsecret); enc64(secrets, 2*c->nsecret, kd, c->nsecret); rv = fprint(c->ctl, "secret %s %s 1 %s", c->digest, c->enc, secrets); memset(secrets, 0, 2*c->nsecret); free(secrets); memset(kd, 0, c->nsecret); if(rv < 0){ tlsError(c, EHandshakeFailure, "can't set keys: %r"); goto Err; } if(creq) { /* send a zero length certificate */ m.tag = HCertificate; if(!msgSend(c, &m, AFlush)) goto Err; msgClear(&m); } /* client key exchange */ m.tag = HClientKeyExchange; m.u.clientKeyExchange.key = makebytes(epm, nepm); free(epm); epm = nil; if(m.u.clientKeyExchange.key == nil) { tlsError(c, EHandshakeFailure, "can't set secret: %r"); goto Err; } if(!msgSend(c, &m, AFlush)) goto Err; msgClear(&m); /* change cipher spec */ if(fprint(c->ctl, "changecipher") < 0){ tlsError(c, EInternalError, "can't enable cipher: %r"); goto Err; } // Cipherchange must occur immediately before Finished to avoid // potential hole; see section 4.3 of Wagner Schneier 1996. if(tlsSecFinished(c->sec, c->hsmd5, c->hssha1, c->finished.verify, c->finished.n, 1) < 0){ tlsError(c, EInternalError, "can't set finished 1: %r"); goto Err; } m.tag = HFinished; m.u.finished = c->finished; if(!msgSend(c, &m, AFlush)) { fprint(2, "tlsClient nepm=%d\n", nepm); tlsError(c, EInternalError, "can't flush after client Finished: %r"); goto Err; } msgClear(&m); if(tlsSecFinished(c->sec, c->hsmd5, c->hssha1, c->finished.verify, c->finished.n, 0) < 0){ fprint(2, "tlsClient nepm=%d\n", nepm); tlsError(c, EInternalError, "can't set finished 0: %r"); goto Err; } if(!msgRecv(c, &m)) { fprint(2, "tlsClient nepm=%d\n", nepm); tlsError(c, EInternalError, "can't read server Finished: %r"); goto Err; } if(m.tag != HFinished) { fprint(2, "tlsClient nepm=%d\n", nepm); tlsError(c, EUnexpectedMessage, "expected a Finished msg from server"); goto Err; } if(!finishedMatch(c, &m.u.finished)) { tlsError(c, EHandshakeFailure, "finished verification failed"); goto Err; } msgClear(&m); if(fprint(c->ctl, "opened") < 0){ if(trace) trace("unable to do final open: %r\n"); goto Err; } tlsSecOk(c->sec); return c;Err: free(epm); msgClear(&m); tlsConnectionFree(c); return 0;}//================= message functions ========================static uchar sendbuf[9000], *sendp;static intmsgSend(TlsConnection *c, Msg *m, int act){ uchar *p; // sendp = start of new message; p = write pointer int nn, n, i; if(sendp == nil) sendp = sendbuf; p = sendp; if(c->trace) c->trace("send %s", msgPrint((char*)p, (sizeof sendbuf) - (p-sendbuf), m)); p[0] = m->tag; // header - fill in size later p += 4; switch(m->tag) { default: tlsError(c, EInternalError, "can't encode a %d", m->tag); goto Err; case HClientHello: // version put16(p, m->u.clientHello.version); p += 2; // random memmove(p, m->u.clientHello.random, RandomSize); p += RandomSize; // sid n = m->u.clientHello.sid->len; assert(n < 256); p[0] = n; memmove(p+1, m->u.clientHello.sid->data, n); p += n+1; n = m->u.clientHello.ciphers->len; assert(n > 0 && n < 200); put16(p, n*2); p += 2; for(i=0; i<n; i++) { put16(p, m->u.clientHello.ciphers->data[i]); p += 2; } n = m->u.clientHello.compressors->len; assert(n > 0); p[0] = n; memmove(p+1, m->u.clientHello.compressors->data, n); p += n+1; break; case HServerHello: put16(p, m->u.serverHello.version); p += 2; // random memmove(p, m->u.serverHello.random, RandomSize); p += RandomSize; // sid n = m->u.serverHello.sid->len; assert(n < 256); p[0] = n; memmove(p+1, m->u.serverHello.sid->data, n); p += n+1; put16(p, m->u.serverHello.cipher); p += 2; p[0] = m->u.serverHello.compressor; p += 1; break; case HServerHelloDone: break; case HCertificate: nn = 0; for(i = 0; i < m->u.certificate.ncert; i++) nn += 3 + m->u.certificate.certs[i]->len; if(p + 3 + nn - sendbuf > sizeof(sendbuf)) { tlsError(c, EInternalError, "output buffer too small for certificate"); goto Err; } put24(p, nn); p += 3; for(i = 0; i < m->u.certificate.ncert; i++){ put24(p, m->u.certificate.certs[i]->len); p += 3; memmove(p, m->u.certificate.certs[i]->data, m->u.certificate.certs[i]->len); p += m->u.certificate.certs[i]->len; } break; case HClientKeyExchange: n = m->u.clientKeyExchange.key->len; if(c->version != SSL3Version){ put16(p, n); p += 2; } memmove(p, m->u.clientKeyExchange.key->data, n); p += n; break; case HFinished: memmove(p, m->u.finished.verify, m->u.finished.n); p += m->u.finished.n; break; } // go back and fill in size n = p-sendp; assert(p <= sendbuf+sizeof(sendbuf)); put24(sendp+1, n-4); // remember hash of Handshake messages if(m->tag != HHelloRequest) { md5(sendp, n, 0, &c->hsmd5); sha1(sendp, n, 0, &c->hssha1); } sendp = p; if(act == AFlush){ sendp = sendbuf; if(write(c->hand, sendbuf, p-sendbuf) < 0){ fprint(2, "write error: %r\n"); goto Err; } } msgClear(m); return 1;Err: msgClear(m); return 0;}static uchar*tlsReadN(TlsConnection *c, int n){ uchar *p; int nn, nr; nn = c->ep - c->rp; if(nn < n){ if(c->rp != c->buf){ memmove(c->buf, c->rp, nn); c->rp = c->buf; c->ep = &c->buf[nn]; } for(; nn < n; nn += nr) { nr = read(c->hand, &c->rp[nn], n - nn); if(nr <= 0) return nil; c->ep += nr; } } p = c->rp; c->rp += n; return p;}static intmsgRecv(TlsConnection *c, Msg *m){ uchar *p; int type, n, nn, i, nsid, nrandom, nciph; for(;;) { p = tlsReadN(c, 4); if(p == nil) return 0; type = p[0]; n = get24(p+1); if(type != HHelloRequest) break; if(n != 0) { tlsError(c, EDecodeError, "invalid hello request during handshake"); return 0; } } if(n > sizeof(c->buf)) { tlsError(c, EDecodeError, "handshake message too long %d %d", n, sizeof(c->buf)); return 0; } if(type == HSSL2ClientHello){ /* Cope with an SSL3 ClientHello expressed in SSL2 record format. This is sent by some clients that we must interoperate with, such as Java's JSSE and Microsoft's Internet Explorer. */ p = tlsReadN(c, n); if(p == nil) return 0; md5(p, n, 0, &c->hsmd5); sha1(p, n, 0, &c->hssha1); m->tag = HClientHello; if(n < 22) goto Short; m->u.clientHello.version = get16(p+1); p += 3; n -= 3; nn = get16(p); /* cipher_spec_len */ nsid = get16(p + 2); nrandom = get16(p + 4); p += 6; n -= 6; if(nsid != 0 /* no sid's, since shouldn't restart using ssl2 header */ || nrandom < 16 || nn % 3) goto Err; if(c->trace && (n - nrandom != nn)) c->trace("n-nrandom!=nn: n=%d nrandom=%d nn=%d\n", n, nrandom, nn); /* ignore ssl2 ciphers and look for {0x00, ssl3 cipher} */ nciph = 0; for(i = 0; i < nn; i += 3) if(p[i] == 0) nciph++; m->u.clientHello.ciphers = newints(nciph); nciph = 0; for(i = 0; i < nn; i += 3) if(p[i] == 0) m->u.clientHello.ciphers->data[nciph++] = get16(&p[i + 1]); p += nn; m->u.clientHello.sid = makebytes(nil, 0); if(nrandom > RandomSize) nrandom = RandomSize; memset(m->u.clientHello.random, 0, RandomSize - nrandom); memmove(&m->u.clientHello.random[RandomSize - nrandom], p, nrandom); m->u.clientHello.compressors = newbytes(1); m->u.clientHello.compressors->data[0] = CompressionNull; goto Ok; } md5(p, 4, 0, &c->hsmd5); sha1(p, 4, 0, &c->hssha1); p = tlsReadN(c, n); if(p == nil) return 0; md5(p, n, 0, &c->hsmd5); sha1(p, n, 0, &c->hssha1); m->tag = type; switch(type) { default: tlsError(c, EUnexpectedMessage, "can't decode a %d", type); goto Err; case HClientHello: if(n < 2) goto Short; m->u.clientHello.version = get16(p); p += 2; n -= 2; if(n < RandomSize) goto Short; memmove(m->u.clientHello.random, p, RandomSize); p += RandomSize; n -= RandomSize; if(n < 1 || n < p[0]+1) goto Short; m->u.clientHello.sid = makebytes(p+1, p[0]); p += m->u.clientHello.sid->len+1; n -= m->u.clientHello.sid->len+1; if(n < 2) goto Short; nn = get16(p); p += 2; n -= 2; if((nn & 1) || n < nn || nn < 2) goto Short; m->u.clientHello.ciphers = newints(nn >> 1); for(i = 0; i < nn; i += 2) m->u.clientHello.ciphers->data[i >> 1] = get16(&p[i]); p += nn; n -= nn; if(n < 1 || n < p[0]+1 || p[0] == 0) goto Short; nn = p[0]; m->u.clientHello.compressors = newbytes(nn); memmove(m->u.clientHello.compressors->data, p+1, nn); n -= nn + 1; break; case HServerHello: if(n < 2) goto Short; m->u.serverHello.version = get16(p); p += 2; n -= 2; if(n < RandomSize) goto Short; memmove(m->u.serverHello.random, p, RandomSize); p += RandomSize; n -= RandomSize; if(n < 1 || n < p[0]+1) goto Short; m->u.serverHello.sid = makebytes(p+1, p[0]); p += m->u.serverHello.sid->len+1; n -= m->u.serverHello.sid->len+1; if(n < 3) goto Short; m->u.serverHello.cipher = get16(p); m->u.serverHello.compressor = p[2]; n -= 3; break; case HCertificate: if(n < 3) goto Short; nn = get24(p); p += 3; n -= 3; if(n != nn) goto Short; /* certs */ i = 0; while(n > 0) { if(n < 3) goto Short; nn = get24(p); p += 3; n -= 3; if(nn > n) goto Short; m->u.certificate.ncert = i+1; m->u.certificate.certs = erealloc(m->u.certificate.certs, (i+1)*sizeof(Bytes)); m->u.certificate.certs[i] = makebytes(p, nn); p += nn; n -= nn; i++; } break; case HCertificateRequest: if(n < 1) goto Short; nn = p[0]; p += 1; n -= 1; if(nn < 1 || nn > n) goto Short; m->u.certificateRequest.types = makebytes(p, nn); p += nn; n -= nn; if(n < 2) goto Short; nn = get16(p); p += 2; n -= 2; if(nn == 0 || n != nn) goto Short; /* cas */ i = 0; while(n > 0) { if(n < 2) goto Short; nn = get16(p);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -