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

📄 tlshand.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 4 页
字号:
#include <u.h>#include <libc.h>#include <bio.h>#include <auth.h>#include <mp.h>#include <libsec.h>// The main groups of functions are://		client/server - main handshake protocol definition//		message functions - formating handshake messages//		cipher choices - catalog of digest and encrypt algorithms//		security functions - PKCS#1, sslHMAC, session keygen//		general utility functions - malloc, serialization// The handshake protocol builds on the TLS/SSL3 record layer protocol,// which is implemented in kernel device #a.  See also /lib/rfc/rfc2246.enum {	TLSFinishedLen = 12,	SSL3FinishedLen = MD5dlen+SHA1dlen,	MaxKeyData = 104,	// amount of secret we may need	MaxChunk = 1<<14,	RandomSize = 32,	SidSize = 32,	MasterSecretSize = 48,	AQueue = 0,	AFlush = 1,};typedef struct TlsSec TlsSec;typedef struct Bytes{	int len;	uchar data[1];  // [len]} Bytes;typedef struct Ints{	int len;	int data[1];  // [len]} Ints;typedef struct Algs{	char *enc;	char *digest;	int nsecret;	int tlsid;	int ok;} Algs;typedef struct Finished{	uchar verify[SSL3FinishedLen];	int n;} Finished;typedef struct TlsConnection{	TlsSec *sec;	// security management goo	int hand, ctl;	// record layer file descriptors	int erred;		// set when tlsError called	int (*trace)(char*fmt, ...); // for debugging	int version;	// protocol we are speaking	int verset;		// version has been set	int ver2hi;		// server got a version 2 hello	int isClient;	// is this the client or server?	Bytes *sid;		// SessionID	Bytes *cert;	// only last - no chain	Lock statelk;	int state;		// must be set using setstate	// input buffer for handshake messages	uchar buf[MaxChunk+2048];	uchar *rp, *ep;	uchar crandom[RandomSize];	// client random	uchar srandom[RandomSize];	// server random	int clientVersion;	// version in ClientHello	char *digest;	// name of digest algorithm to use	char *enc;		// name of encryption algorithm to use	int nsecret;	// amount of secret data to init keys	// for finished messages	MD5state	hsmd5;	// handshake hash	SHAstate	hssha1;	// handshake hash	Finished	finished;} TlsConnection;typedef struct Msg{	int tag;	union {		struct {			int version;			uchar 	random[RandomSize];			Bytes*	sid;			Ints*	ciphers;			Bytes*	compressors;		} clientHello;		struct {			int version;			uchar 	random[RandomSize];			Bytes*	sid;			int cipher;			int compressor;		} serverHello;		struct {			int ncert;			Bytes **certs;		} certificate;		struct {			Bytes *types;			int nca;			Bytes **cas;		} certificateRequest;		struct {			Bytes *key;		} clientKeyExchange;		Finished finished;	} u;} Msg;typedef struct TlsSec{	char *server;	// name of remote; nil for server	int ok;	// <0 killed; == 0 in progress; >0 reusable	RSApub *rsapub;	AuthRpc *rpc;	// factotum for rsa private key	uchar sec[MasterSecretSize];	// master secret	uchar crandom[RandomSize];	// client random	uchar srandom[RandomSize];	// server random	int clientVers;		// version in ClientHello	int vers;			// final version	// byte generation and handshake checksum	void (*prf)(uchar*, int, uchar*, int, char*, uchar*, int, uchar*, int);	void (*setFinished)(TlsSec*, MD5state, SHAstate, uchar*, int);	int nfin;} TlsSec;enum {	TLSVersion = 0x0301,	SSL3Version = 0x0300,	ProtocolVersion = 0x0301,	// maximum version we speak	MinProtoVersion = 0x0300,	// limits on version we accept	MaxProtoVersion	= 0x03ff,};// handshake typeenum {	HHelloRequest,	HClientHello,	HServerHello,	HSSL2ClientHello = 9,  /* local convention;  see devtls.c */	HCertificate = 11,	HServerKeyExchange,	HCertificateRequest,	HServerHelloDone,	HCertificateVerify,	HClientKeyExchange,	HFinished = 20,	HMax};// alertsenum {	ECloseNotify = 0,	EUnexpectedMessage = 10,	EBadRecordMac = 20,	EDecryptionFailed = 21,	ERecordOverflow = 22,	EDecompressionFailure = 30,	EHandshakeFailure = 40,	ENoCertificate = 41,	EBadCertificate = 42,	EUnsupportedCertificate = 43,	ECertificateRevoked = 44,	ECertificateExpired = 45,	ECertificateUnknown = 46,	EIllegalParameter = 47,	EUnknownCa = 48,	EAccessDenied = 49,	EDecodeError = 50,	EDecryptError = 51,	EExportRestriction = 60,	EProtocolVersion = 70,	EInsufficientSecurity = 71,	EInternalError = 80,	EUserCanceled = 90,	ENoRenegotiation = 100,	EMax = 256};// cipher suitesenum {	TLS_NULL_WITH_NULL_NULL	 		= 0x0000,	TLS_RSA_WITH_NULL_MD5 			= 0x0001,	TLS_RSA_WITH_NULL_SHA 			= 0x0002,	TLS_RSA_EXPORT_WITH_RC4_40_MD5 		= 0x0003,	TLS_RSA_WITH_RC4_128_MD5 		= 0x0004,	TLS_RSA_WITH_RC4_128_SHA 		= 0x0005,	TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5	= 0X0006,	TLS_RSA_WITH_IDEA_CBC_SHA 		= 0X0007,	TLS_RSA_EXPORT_WITH_DES40_CBC_SHA	= 0X0008,	TLS_RSA_WITH_DES_CBC_SHA		= 0X0009,	TLS_RSA_WITH_3DES_EDE_CBC_SHA		= 0X000A,	TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA	= 0X000B,	TLS_DH_DSS_WITH_DES_CBC_SHA		= 0X000C,	TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA	= 0X000D,	TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA	= 0X000E,	TLS_DH_RSA_WITH_DES_CBC_SHA		= 0X000F,	TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA	= 0X0010,	TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA	= 0X0011,	TLS_DHE_DSS_WITH_DES_CBC_SHA		= 0X0012,	TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA	= 0X0013,	// ZZZ must be implemented for tls1.0 compliance	TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA	= 0X0014,	TLS_DHE_RSA_WITH_DES_CBC_SHA		= 0X0015,	TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA	= 0X0016,	TLS_DH_anon_EXPORT_WITH_RC4_40_MD5	= 0x0017,	TLS_DH_anon_WITH_RC4_128_MD5 		= 0x0018,	TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA	= 0X0019,	TLS_DH_anon_WITH_DES_CBC_SHA		= 0X001A,	TLS_DH_anon_WITH_3DES_EDE_CBC_SHA	= 0X001B,	TLS_RSA_WITH_AES_128_CBC_SHA		= 0X002f,	// aes, aka rijndael with 128 bit blocks	TLS_DH_DSS_WITH_AES_128_CBC_SHA		= 0X0030,	TLS_DH_RSA_WITH_AES_128_CBC_SHA		= 0X0031,	TLS_DHE_DSS_WITH_AES_128_CBC_SHA	= 0X0032,	TLS_DHE_RSA_WITH_AES_128_CBC_SHA	= 0X0033,	TLS_DH_anon_WITH_AES_128_CBC_SHA	= 0X0034,	TLS_RSA_WITH_AES_256_CBC_SHA		= 0X0035,	TLS_DH_DSS_WITH_AES_256_CBC_SHA		= 0X0036,	TLS_DH_RSA_WITH_AES_256_CBC_SHA		= 0X0037,	TLS_DHE_DSS_WITH_AES_256_CBC_SHA	= 0X0038,	TLS_DHE_RSA_WITH_AES_256_CBC_SHA	= 0X0039,	TLS_DH_anon_WITH_AES_256_CBC_SHA	= 0X003A,	CipherMax};// compression methodsenum {	CompressionNull = 0,	CompressionMax};static Algs cipherAlgs[] = {	{"rc4_128", "md5",	2 * (16 + MD5dlen), TLS_RSA_WITH_RC4_128_MD5},	{"rc4_128", "sha1",	2 * (16 + SHA1dlen), TLS_RSA_WITH_RC4_128_SHA},	{"3des_ede_cbc","sha1",2*(4*8+SHA1dlen), TLS_RSA_WITH_3DES_EDE_CBC_SHA},};static uchar compressors[] = {	CompressionNull,};static TlsConnection *tlsServer2(int ctl, int hand, uchar *cert, int ncert, int (*trace)(char*fmt, ...), PEMChain *chain);static TlsConnection *tlsClient2(int ctl, int hand, uchar *csid, int ncsid, int (*trace)(char*fmt, ...));static void	msgClear(Msg *m);static char* msgPrint(char *buf, int n, Msg *m);static int	msgRecv(TlsConnection *c, Msg *m);static int	msgSend(TlsConnection *c, Msg *m, int act);static void	tlsError(TlsConnection *c, int err, char *msg, ...);#pragma	varargck argpos	tlsError 3static int setVersion(TlsConnection *c, int version);static int finishedMatch(TlsConnection *c, Finished *f);static void tlsConnectionFree(TlsConnection *c);static int setAlgs(TlsConnection *c, int a);static int okCipher(Ints *cv);static int okCompression(Bytes *cv);static int initCiphers(void);static Ints* makeciphers(void);static TlsSec* tlsSecInits(int cvers, uchar *csid, int ncsid, uchar *crandom, uchar *ssid, int *nssid, uchar *srandom);static int	tlsSecSecrets(TlsSec *sec, int vers, uchar *epm, int nepm, uchar *kd, int nkd);static TlsSec*	tlsSecInitc(int cvers, uchar *crandom);static int	tlsSecSecretc(TlsSec *sec, uchar *sid, int nsid, uchar *srandom, uchar *cert, int ncert, int vers, uchar **epm, int *nepm, uchar *kd, int nkd);static int	tlsSecFinished(TlsSec *sec, MD5state md5, SHAstate sha1, uchar *fin, int nfin, int isclient);static void	tlsSecOk(TlsSec *sec);static void	tlsSecKill(TlsSec *sec);static void	tlsSecClose(TlsSec *sec);static void	setMasterSecret(TlsSec *sec, Bytes *pm);static void	serverMasterSecret(TlsSec *sec, uchar *epm, int nepm);static void	setSecrets(TlsSec *sec, uchar *kd, int nkd);static int	clientMasterSecret(TlsSec *sec, RSApub *pub, uchar **epm, int *nepm);static Bytes *pkcs1_encrypt(Bytes* data, RSApub* key, int blocktype);static Bytes *pkcs1_decrypt(TlsSec *sec, uchar *epm, int nepm);static void	tlsSetFinished(TlsSec *sec, MD5state hsmd5, SHAstate hssha1, uchar *finished, int isClient);static void	sslSetFinished(TlsSec *sec, MD5state hsmd5, SHAstate hssha1, uchar *finished, int isClient);static void	sslPRF(uchar *buf, int nbuf, uchar *key, int nkey, char *label,			uchar *seed0, int nseed0, uchar *seed1, int nseed1);static int setVers(TlsSec *sec, int version);static AuthRpc* factotum_rsa_open(uchar *cert, int certlen);static mpint* factotum_rsa_decrypt(AuthRpc *rpc, mpint *cipher);static void factotum_rsa_close(AuthRpc*rpc);static void* emalloc(int);static void* erealloc(void*, int);static void put32(uchar *p, u32int);static void put24(uchar *p, int);static void put16(uchar *p, int);static u32int get32(uchar *p);static int get24(uchar *p);static int get16(uchar *p);static Bytes* newbytes(int len);static Bytes* makebytes(uchar* buf, int len);static void freebytes(Bytes* b);static Ints* newints(int len);static Ints* makeints(int* buf, int len);static void freeints(Ints* b);//================= client/server ========================//	push TLS onto fd, returning new (application) file descriptor//		or -1 if error.inttlsServer(int fd, TLSconn *conn){	char buf[8];	char dname[64];	int n, data, ctl, hand;	TlsConnection *tls;	if(conn == nil)		return -1;	ctl = open("#a/tls/clone", ORDWR);	if(ctl < 0)		return -1;	n = read(ctl, buf, sizeof(buf)-1);	if(n < 0){		close(ctl);		return -1;	}	buf[n] = 0;	sprint(conn->dir, "#a/tls/%s", buf);	sprint(dname, "#a/tls/%s/hand", buf);	hand = open(dname, ORDWR);	if(hand < 0){		close(ctl);		return -1;	}	fprint(ctl, "fd %d 0x%x", fd, ProtocolVersion);	tls = tlsServer2(ctl, hand, conn->cert, conn->certlen, conn->trace, conn->chain);	sprint(dname, "#a/tls/%s/data", buf);	data = open(dname, ORDWR);	close(fd);	close(hand);	close(ctl);	if(data < 0){		return -1;	}	if(tls == nil){		close(data);		return -1;	}	if(conn->cert)		free(conn->cert);	conn->cert = 0;  // client certificates are not yet implemented	conn->certlen = 0;	conn->sessionIDlen = tls->sid->len;	conn->sessionID = emalloc(conn->sessionIDlen);	memcpy(conn->sessionID, tls->sid->data, conn->sessionIDlen);	if(conn->sessionKey != nil && conn->sessionType != nil && strcmp(conn->sessionType, "ttls") == 0)		tls->sec->prf(conn->sessionKey, conn->sessionKeylen, tls->sec->sec, MasterSecretSize, conn->sessionConst,  tls->sec->crandom, RandomSize, tls->sec->srandom, RandomSize);	tlsConnectionFree(tls);	return data;}//	push TLS onto fd, returning new (application) file descriptor//		or -1 if error.inttlsClient(int fd, TLSconn *conn){	char buf[8];	char dname[64];	int n, data, ctl, hand;	TlsConnection *tls;	if(!conn)		return -1;	ctl = open("#a/tls/clone", ORDWR);	if(ctl < 0)		return -1;	n = read(ctl, buf, sizeof(buf)-1);	if(n < 0){		close(ctl);		return -1;	}	buf[n] = 0;	sprint(conn->dir, "#a/tls/%s", buf);	sprint(dname, "#a/tls/%s/hand", buf);	hand = open(dname, ORDWR);	if(hand < 0){		close(ctl);		return -1;	}	sprint(dname, "#a/tls/%s/data", buf);	data = open(dname, ORDWR);	if(data < 0)		return -1;	fprint(ctl, "fd %d 0x%x", fd, ProtocolVersion);	tls = tlsClient2(ctl, hand, conn->sessionID, conn->sessionIDlen, conn->trace);	close(fd);	close(hand);	close(ctl);	if(tls == nil){		close(data);		return -1;	}	conn->certlen = tls->cert->len;	conn->cert = emalloc(conn->certlen);	memcpy(conn->cert, tls->cert->data, conn->certlen);	conn->sessionIDlen = tls->sid->len;	conn->sessionID = emalloc(conn->sessionIDlen);	memcpy(conn->sessionID, tls->sid->data, conn->sessionIDlen);	if(conn->sessionKey != nil && conn->sessionType != nil && strcmp(conn->sessionType, "ttls") == 0)		tls->sec->prf(conn->sessionKey, conn->sessionKeylen, tls->sec->sec, MasterSecretSize, conn->sessionConst,  tls->sec->crandom, RandomSize, tls->sec->srandom, RandomSize);	tlsConnectionFree(tls);	return data;}static intcountchain(PEMChain *p){	int i = 0;	while (p) {		i++;		p = p->next;	}	return i;}static TlsConnection *tlsServer2(int ctl, int hand, uchar *cert, int ncert, int (*trace)(char*fmt, ...), PEMChain *chp){	TlsConnection *c;	Msg m;	Bytes *csid;	uchar sid[SidSize], kd[MaxKeyData];	char *secrets;	int cipher, compressor, nsid, rv, numcerts, i;	if(trace)		trace("tlsServer2\n");	if(!initCiphers())		return nil;	c = emalloc(sizeof(TlsConnection));	c->ctl = ctl;	c->hand = hand;	c->trace = trace;	c->version = ProtocolVersion;	memset(&m, 0, sizeof(m));	if(!msgRecv(c, &m)){		if(trace)			trace("initial msgRecv failed\n");		goto Err;	}	if(m.tag != HClientHello) {		tlsError(c, EUnexpectedMessage, "expected a client hello");		goto Err;	}	c->clientVersion = m.u.clientHello.version;	if(trace)		trace("ClientHello version %x\n", c->clientVersion);	if(setVersion(c, m.u.clientHello.version) < 0) {		tlsError(c, EIllegalParameter, "incompatible version");		goto Err;	}	memmove(c->crandom, m.u.clientHello.random, RandomSize);	cipher = okCipher(m.u.clientHello.ciphers);	if(cipher < 0) {		// reply with EInsufficientSecurity if we know that's the case		if(cipher == -2)			tlsError(c, EInsufficientSecurity, "cipher suites too weak");		else			tlsError(c, EHandshakeFailure, "no matching cipher suite");		goto Err;	}	if(!setAlgs(c, cipher)){		tlsError(c, EHandshakeFailure, "no matching cipher suite");		goto Err;	}	compressor = okCompression(m.u.clientHello.compressors);	if(compressor < 0) {		tlsError(c, EHandshakeFailure, "no matching compressor");		goto Err;	}	csid = m.u.clientHello.sid;	if(trace)		trace("  cipher %d, compressor %d, csidlen %d\n", cipher, compressor, csid->len);	c->sec = tlsSecInits(c->clientVersion, csid->data, csid->len, c->crandom, sid, &nsid, c->srandom);	if(c->sec == nil){		tlsError(c, EHandshakeFailure, "can't initialize security: %r");		goto Err;	}	c->sec->rpc = factotum_rsa_open(cert, ncert);	if(c->sec->rpc == nil){		tlsError(c, EHandshakeFailure, "factotum_rsa_open: %r");		goto Err;	}	c->sec->rsapub = X509toRSApub(cert, ncert, nil, 0);	msgClear(&m);	m.tag = HServerHello;	m.u.serverHello.version = c->version;	memmove(m.u.serverHello.random, c->srandom, RandomSize);	m.u.serverHello.cipher = cipher;	m.u.serverHello.compressor = compressor;	c->sid = makebytes(sid, nsid);	m.u.serverHello.sid = makebytes(c->sid->data, c->sid->len);	if(!msgSend(c, &m, AQueue))		goto Err;	msgClear(&m);	m.tag = HCertificate;	numcerts = countchain(chp);	m.u.certificate.ncert = 1 + numcerts;	m.u.certificate.certs = emalloc(m.u.certificate.ncert * sizeof(Bytes));	m.u.certificate.certs[0] = makebytes(cert, ncert);	for (i = 0; i < numcerts && chp; i++, chp = chp->next)		m.u.certificate.certs[i+1] = makebytes(chp->pem, chp->pemlen);	if(!msgSend(c, &m, AQueue))		goto Err;	msgClear(&m);	m.tag = HServerHelloDone;	if(!msgSend(c, &m, AFlush))		goto Err;	msgClear(&m);	if(!msgRecv(c, &m))		goto Err;	if(m.tag != HClientKeyExchange) {		tlsError(c, EUnexpectedMessage, "expected a client key exchange");		goto Err;	}	if(tlsSecSecrets(c->sec, c->version, m.u.clientKeyExchange.key->data, m.u.clientKeyExchange.key->len, kd, c->nsecret) < 0){		tlsError(c, EHandshakeFailure, "couldn't set secrets: %r");		goto Err;	}	if(trace)		trace("tls secrets\n");	secrets = (char*)emalloc(2*c->nsecret);	enc64(secrets, 2*c->nsecret, kd, c->nsecret);	rv = fprint(c->ctl, "secret %s %s 0 %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;	}	msgClear(&m);	/* no CertificateVerify; skip to Finished */	if(tlsSecFinished(c->sec, c->hsmd5, c->hssha1, c->finished.verify, c->finished.n, 1) < 0){		tlsError(c, EInternalError, "can't set finished: %r");		goto Err;	}	if(!msgRecv(c, &m))		goto Err;	if(m.tag != HFinished) {		tlsError(c, EUnexpectedMessage, "expected a finished");		goto Err;	}	if(!finishedMatch(c, &m.u.finished)) {		tlsError(c, EHandshakeFailure, "finished verification failed");		goto Err;	}	msgClear(&m);	/* change cipher spec */	if(fprint(c->ctl, "changecipher") < 0){		tlsError(c, EInternalError, "can't enable cipher: %r");		goto Err;	}	if(tlsSecFinished(c->sec, c->hsmd5, c->hssha1, c->finished.verify, c->finished.n, 0) < 0){		tlsError(c, EInternalError, "can't set finished: %r");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -