⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tlshand.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 4 页
字号:
		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 + -