📄 tlshand.c
字号:
#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 + -