📄 tlshand.c
字号:
p += 2; n -= 2; if(nn < 1 || nn > n) goto Short; m->u.certificateRequest.nca = i+1; m->u.certificateRequest.cas = erealloc(m->u.certificateRequest.cas, (i+1)*sizeof(Bytes)); m->u.certificateRequest.cas[i] = makebytes(p, nn); p += nn; n -= nn; i++; } break; case HServerHelloDone: break; case HClientKeyExchange: /* * this message depends upon the encryption selected * assume rsa. */ if(c->version == SSL3Version) nn = n; else{ if(n < 2) goto Short; nn = get16(p); p += 2; n -= 2; } if(n < nn) goto Short; m->u.clientKeyExchange.key = makebytes(p, nn); n -= nn; break; case HFinished: m->u.finished.n = c->finished.n; if(n < m->u.finished.n) goto Short; memmove(m->u.finished.verify, p, m->u.finished.n); n -= m->u.finished.n; break; } if(type != HClientHello && n != 0) goto Short;Ok: if(c->trace){ char *buf; buf = emalloc(8000); c->trace("recv %s", msgPrint(buf, 8000, m)); free(buf); } return 1;Short: tlsError(c, EDecodeError, "handshake message has invalid length");Err: msgClear(m); return 0;}static voidmsgClear(Msg *m){ int i; switch(m->tag) { default: sysfatal("msgClear: unknown message type: %d\n", m->tag); case HHelloRequest: break; case HClientHello: freebytes(m->u.clientHello.sid); freeints(m->u.clientHello.ciphers); freebytes(m->u.clientHello.compressors); break; case HServerHello: freebytes(m->u.clientHello.sid); break; case HCertificate: for(i=0; i<m->u.certificate.ncert; i++) freebytes(m->u.certificate.certs[i]); free(m->u.certificate.certs); break; case HCertificateRequest: freebytes(m->u.certificateRequest.types); for(i=0; i<m->u.certificateRequest.nca; i++) freebytes(m->u.certificateRequest.cas[i]); free(m->u.certificateRequest.cas); break; case HServerHelloDone: break; case HClientKeyExchange: freebytes(m->u.clientKeyExchange.key); break; case HFinished: break; } memset(m, 0, sizeof(Msg));}static char *bytesPrint(char *bs, char *be, char *s0, Bytes *b, char *s1){ int i; if(s0) bs = seprint(bs, be, "%s", s0); bs = seprint(bs, be, "["); if(b == nil) bs = seprint(bs, be, "nil"); else for(i=0; i<b->len; i++) bs = seprint(bs, be, "%.2x ", b->data[i]); bs = seprint(bs, be, "]"); if(s1) bs = seprint(bs, be, "%s", s1); return bs;}static char *intsPrint(char *bs, char *be, char *s0, Ints *b, char *s1){ int i; if(s0) bs = seprint(bs, be, "%s", s0); bs = seprint(bs, be, "["); if(b == nil) bs = seprint(bs, be, "nil"); else for(i=0; i<b->len; i++) bs = seprint(bs, be, "%x ", b->data[i]); bs = seprint(bs, be, "]"); if(s1) bs = seprint(bs, be, "%s", s1); return bs;}static char*msgPrint(char *buf, int n, Msg *m){ int i; char *bs = buf, *be = buf+n; switch(m->tag) { default: bs = seprint(bs, be, "unknown %d\n", m->tag); break; case HClientHello: bs = seprint(bs, be, "ClientHello\n"); bs = seprint(bs, be, "\tversion: %.4x\n", m->u.clientHello.version); bs = seprint(bs, be, "\trandom: "); for(i=0; i<RandomSize; i++) bs = seprint(bs, be, "%.2x", m->u.clientHello.random[i]); bs = seprint(bs, be, "\n"); bs = bytesPrint(bs, be, "\tsid: ", m->u.clientHello.sid, "\n"); bs = intsPrint(bs, be, "\tciphers: ", m->u.clientHello.ciphers, "\n"); bs = bytesPrint(bs, be, "\tcompressors: ", m->u.clientHello.compressors, "\n"); break; case HServerHello: bs = seprint(bs, be, "ServerHello\n"); bs = seprint(bs, be, "\tversion: %.4x\n", m->u.serverHello.version); bs = seprint(bs, be, "\trandom: "); for(i=0; i<RandomSize; i++) bs = seprint(bs, be, "%.2x", m->u.serverHello.random[i]); bs = seprint(bs, be, "\n"); bs = bytesPrint(bs, be, "\tsid: ", m->u.serverHello.sid, "\n"); bs = seprint(bs, be, "\tcipher: %.4x\n", m->u.serverHello.cipher); bs = seprint(bs, be, "\tcompressor: %.2x\n", m->u.serverHello.compressor); break; case HCertificate: bs = seprint(bs, be, "Certificate\n"); for(i=0; i<m->u.certificate.ncert; i++) bs = bytesPrint(bs, be, "\t", m->u.certificate.certs[i], "\n"); break; case HCertificateRequest: bs = seprint(bs, be, "CertificateRequest\n"); bs = bytesPrint(bs, be, "\ttypes: ", m->u.certificateRequest.types, "\n"); bs = seprint(bs, be, "\tcertificateauthorities\n"); for(i=0; i<m->u.certificateRequest.nca; i++) bs = bytesPrint(bs, be, "\t\t", m->u.certificateRequest.cas[i], "\n"); break; case HServerHelloDone: bs = seprint(bs, be, "ServerHelloDone\n"); break; case HClientKeyExchange: bs = seprint(bs, be, "HClientKeyExchange\n"); bs = bytesPrint(bs, be, "\tkey: ", m->u.clientKeyExchange.key, "\n"); break; case HFinished: bs = seprint(bs, be, "HFinished\n"); for(i=0; i<m->u.finished.n; i++) bs = seprint(bs, be, "%.2x", m->u.finished.verify[i]); bs = seprint(bs, be, "\n"); break; } USED(bs); return buf;}static voidtlsError(TlsConnection *c, int err, char *fmt, ...){ char msg[512]; va_list arg; va_start(arg, fmt); vseprint(msg, msg+sizeof(msg), fmt, arg); va_end(arg); if(c->trace) c->trace("tlsError: %s\n", msg); else if(c->erred) fprint(2, "double error: %r, %s", msg); else werrstr("tls: local %s", msg); c->erred = 1; fprint(c->ctl, "alert %d", err);}// commit to specific version numberstatic intsetVersion(TlsConnection *c, int version){ if(c->verset || version > MaxProtoVersion || version < MinProtoVersion) return -1; if(version > c->version) version = c->version; if(version == SSL3Version) { c->version = version; c->finished.n = SSL3FinishedLen; }else if(version == TLSVersion){ c->version = version; c->finished.n = TLSFinishedLen; }else return -1; c->verset = 1; return fprint(c->ctl, "version 0x%x", version);}// confirm that received Finished message matches the expected valuestatic intfinishedMatch(TlsConnection *c, Finished *f){ return memcmp(f->verify, c->finished.verify, f->n) == 0;}// free memory associated with TlsConnection struct// (but don't close the TLS channel itself)static voidtlsConnectionFree(TlsConnection *c){ tlsSecClose(c->sec); freebytes(c->sid); freebytes(c->cert); memset(c, 0, sizeof(c)); free(c);}//================= cipher choices ========================static int weakCipher[CipherMax] ={ 1, /* TLS_NULL_WITH_NULL_NULL */ 1, /* TLS_RSA_WITH_NULL_MD5 */ 1, /* TLS_RSA_WITH_NULL_SHA */ 1, /* TLS_RSA_EXPORT_WITH_RC4_40_MD5 */ 0, /* TLS_RSA_WITH_RC4_128_MD5 */ 0, /* TLS_RSA_WITH_RC4_128_SHA */ 1, /* TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 */ 0, /* TLS_RSA_WITH_IDEA_CBC_SHA */ 1, /* TLS_RSA_EXPORT_WITH_DES40_CBC_SHA */ 0, /* TLS_RSA_WITH_DES_CBC_SHA */ 0, /* TLS_RSA_WITH_3DES_EDE_CBC_SHA */ 1, /* TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA */ 0, /* TLS_DH_DSS_WITH_DES_CBC_SHA */ 0, /* TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA */ 1, /* TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA */ 0, /* TLS_DH_RSA_WITH_DES_CBC_SHA */ 0, /* TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA */ 1, /* TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA */ 0, /* TLS_DHE_DSS_WITH_DES_CBC_SHA */ 0, /* TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA */ 1, /* TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA */ 0, /* TLS_DHE_RSA_WITH_DES_CBC_SHA */ 0, /* TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA */ 1, /* TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 */ 1, /* TLS_DH_anon_WITH_RC4_128_MD5 */ 1, /* TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA */ 1, /* TLS_DH_anon_WITH_DES_CBC_SHA */ 1, /* TLS_DH_anon_WITH_3DES_EDE_CBC_SHA */};static intsetAlgs(TlsConnection *c, int a){ int i; for(i = 0; i < nelem(cipherAlgs); i++){ if(cipherAlgs[i].tlsid == a){ c->enc = cipherAlgs[i].enc; c->digest = cipherAlgs[i].digest; c->nsecret = cipherAlgs[i].nsecret; if(c->nsecret > MaxKeyData) return 0; return 1; } } return 0;}static intokCipher(Ints *cv){ int weak, i, j, c; weak = 1; for(i = 0; i < cv->len; i++) { c = cv->data[i]; if(c >= CipherMax) weak = 0; else weak &= weakCipher[c]; for(j = 0; j < nelem(cipherAlgs); j++) if(cipherAlgs[j].ok && cipherAlgs[j].tlsid == c) return c; } if(weak) return -2; return -1;}static intokCompression(Bytes *cv){ int i, j, c; for(i = 0; i < cv->len; i++) { c = cv->data[i]; for(j = 0; j < nelem(compressors); j++) { if(compressors[j] == c) return c; } } return -1;}static Lock ciphLock;static int nciphers;static intinitCiphers(void){ enum {MaxAlgF = 1024, MaxAlgs = 10}; char s[MaxAlgF], *flds[MaxAlgs]; int i, j, n, ok; lock(&ciphLock); if(nciphers){ unlock(&ciphLock); return nciphers; } j = open("#a/tls/encalgs", OREAD); if(j < 0){ werrstr("can't open #a/tls/encalgs: %r"); return 0; } n = read(j, s, MaxAlgF-1); close(j); if(n <= 0){ werrstr("nothing in #a/tls/encalgs: %r"); return 0; } s[n] = 0; n = getfields(s, flds, MaxAlgs, 1, " \t\r\n"); for(i = 0; i < nelem(cipherAlgs); i++){ ok = 0; for(j = 0; j < n; j++){ if(strcmp(cipherAlgs[i].enc, flds[j]) == 0){ ok = 1; break; } } cipherAlgs[i].ok = ok; } j = open("#a/tls/hashalgs", OREAD); if(j < 0){ werrstr("can't open #a/tls/hashalgs: %r"); return 0; } n = read(j, s, MaxAlgF-1); close(j); if(n <= 0){ werrstr("nothing in #a/tls/hashalgs: %r"); return 0; } s[n] = 0; n = getfields(s, flds, MaxAlgs, 1, " \t\r\n"); for(i = 0; i < nelem(cipherAlgs); i++){ ok = 0; for(j = 0; j < n; j++){ if(strcmp(cipherAlgs[i].digest, flds[j]) == 0){ ok = 1; break; } } cipherAlgs[i].ok &= ok; if(cipherAlgs[i].ok) nciphers++; } unlock(&ciphLock); return nciphers;}static Ints*makeciphers(void){ Ints *is; int i, j; is = newints(nciphers); j = 0; for(i = 0; i < nelem(cipherAlgs); i++){ if(cipherAlgs[i].ok) is->data[j++] = cipherAlgs[i].tlsid; } return is;}//================= security functions ========================// given X.509 certificate, set up connection to factotum// for using corresponding private keystatic AuthRpc*factotum_rsa_open(uchar *cert, int certlen){ int afd; char *s; mpint *pub = nil; RSApub *rsapub; AuthRpc *rpc; // start talking to factotum if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0) return nil; if((rpc = auth_allocrpc(afd)) == nil){ close(afd); return nil; } s = "proto=rsa service=tls role=client"; if(auth_rpc(rpc, "start", s, strlen(s)) != ARok){ factotum_rsa_close(rpc); return nil; } // roll factotum keyring around to match certificate rsapub = X509toRSApub(cert, certlen, nil, 0); while(1){ if(auth_rpc(rpc, "read", nil, 0) != ARok){ factotum_rsa_close(rpc); rpc = nil; goto done; } pub = strtomp(rpc->arg, nil, 16, nil); assert(pub != nil); if(mpcmp(pub,rsapub->n) == 0) break; }done: mpfree(pub); rsapubfree(rsapub); return rpc;}static mpint*factotum_rsa_decrypt(AuthRpc *rpc, mpint *cipher){ char *p; int rv; if((p = mptoa(cipher, 16, nil, 0)) == nil) return nil; rv = auth_rpc(rpc, "write", p, strlen(p)); free(p); if(rv != ARok || auth_rpc(rpc, "read", nil, 0) != ARok) return nil; mpfree(cipher); return strtomp(rpc->arg, nil, 16, nil);}static voidfactotum_rsa_close(AuthRpc*rpc){ if(!rpc) return; close(rpc->afd); auth_freerpc(rpc);}static voidtlsPmd5(uchar *buf, int nbuf, uchar *key, int nkey, uchar *label, int nlabel, uchar *seed0, int nseed0, uchar *seed1, int nseed1){ uchar ai[MD5dlen], tmp[MD5dlen]; int i, n; MD5state *s; // generate a1 s = hmac_md5(label, nlabel, key, nkey, nil, nil); s = hmac_md5(seed0, nseed0, key, nkey, nil, s); hmac_md5(seed1, nseed1, key, nkey, ai, s); while(nbuf > 0) { s = hmac_md5(ai, MD5dlen, key, nkey, nil, nil); s = hmac_md5(label, nlabel, key, nkey, nil, s); s = hmac_md5(seed0, nseed0, key, nkey, nil, s); hmac_md5(seed1, nseed1, key, nkey, tmp, s); n = MD5dlen; if(n > nbuf) n = nbuf; for(i = 0; i < n; i++) buf[i] ^= tmp[i]; buf += n; nbuf -= n; hmac_md5(ai, MD5dlen, key, nkey, tmp, nil); memmove(ai, tmp, MD5dlen); }}static voidtlsPsha1(uchar *buf, int nbuf, uchar *key, int nkey, uchar *label, int nlabel, uchar *seed0, int nseed0, uchar *seed1, int nseed1){ uchar ai[SHA1dlen], tmp[SHA1dlen]; int i, n; SHAstate *s; // generate a1 s = hmac_sha1(label, nlabel, key, nkey, nil, nil); s = hmac_sha1(seed0, nseed0, key, nkey, nil, s); hmac_sha1(seed1, nseed1, key, nkey, ai, s); while(nbuf > 0) { s = hmac_sha1(ai, SHA1dlen, key, nkey, nil, nil); s = hmac_sha1(label, nlabel, key, nkey, nil, s); s = hmac_sha1(seed0, nseed0, key, nkey, nil, s); hmac_sha1(seed1, nseed1, key, nkey, tmp, s); n = SHA1dlen; if(n > nbuf) n = nbuf; for(i = 0; i < n; i++) buf[i] ^= tmp[i]; buf += n; nbuf -= n; hmac_sha1(ai, SHA1dlen, key, nkey, tmp, nil); memmove(ai, tmp, SHA1dlen); }}// fill buf with md5(args)^sha1(args)static voidtlsPRF(uchar *buf, int nbuf, uchar *key, int nkey, char *label, uchar *seed0, int nseed0, uchar *seed1, int nseed1){ int i; int nlabel = strlen(label); int n = (nkey + 1) >> 1; for(i = 0; i < nbuf; i++) buf[i] = 0; tlsPmd5(buf, nbuf, key, n, (uchar*)label, nlabel, seed0, nseed0, seed1, nseed1); tlsPsha1(buf, nbuf, key+nkey-n, n, (uchar*)label, nlabel, seed0, nseed0, seed1, nseed1);}/* * for setting server session id's */static Lock sidLock;static long maxSid = 1;/* the keys are verified to have the same public components
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -