void ParseServerKeyExchangeInner(HMParser hm) { CipherSuite cs; if (!CipherSuite.ALL.TryGetValue(selectedCipherSuite, out cs)) { unknownSKE = true; hm.Close(true); return; } if (cs.IsDHE) { /* * If this is DHE_PSK, then there is first a * "key hint" to skip. */ if (cs.IsPSK) { hm.ReadBlobVar(2); } /* * DH parameters: p, g, y. We are only interested * in p. */ byte[] p = hm.ReadBlobVar(2); dhSize = M.BitLength(p); hm.ReadBlobVar(2); hm.ReadBlobVar(2); if (cs.ServerKeyType != "none") { if (version >= M.TLSv12) { /* * Hash-and-sign identifiers. */ hm.Read2(); } hm.ReadBlobVar(2); } } else if (cs.IsECDHE) { /* * If this is ECDHE_PSK, then there is first a * "key hint" to skip. */ if (cs.IsPSK) { hm.ReadBlobVar(2); } /* * Read curve type: one byte. */ switch (hm.Read1()) { case 1: /* * explicit_prime: p, a, b, G, * order, cofactor. */ hm.ReadBlobVar(1); hm.ReadBlobVar(1); hm.ReadBlobVar(1); hm.ReadBlobVar(1); ecSize = M.AdjustedBitLength(hm.ReadBlobVar(1)); hm.ReadBlobVar(1); curveExplicitPrime = true; break; case 2: /* explicit_char2 */ hm.Read2(); switch (hm.Read1()) { case 1: /* trinomial */ hm.ReadBlobVar(1); break; case 2: /* pentanomial */ hm.ReadBlobVar(1); hm.ReadBlobVar(1); hm.ReadBlobVar(1); break; default: hm.Close(true); unknownSKE = true; return; } hm.ReadBlobVar(1); hm.ReadBlobVar(1); hm.ReadBlobVar(1); ecSize = M.AdjustedBitLength(hm.ReadBlobVar(1)); hm.ReadBlobVar(1); curveExplicitChar2 = true; break; case 3: /* * named_curve. */ int id = hm.Read2(); if (SSLCurve.ALL.TryGetValue(id, out curve)) { ecSize = curve.Size; } else { curve = null; hm.Close(true); unknownSKE = true; return; } break; default: hm.Close(true); unknownSKE = true; return; } /* * Read public key: one curve point. */ hm.ReadBlobVar(1); if (cs.ServerKeyType != "none") { if (version >= M.TLSv12) { /* * Hash-and-sign identifiers. */ hm.Read2(); } hm.ReadBlobVar(2); } } else if (cs.IsRSAExport) { /* * If cipher suite uses RSA key exchange and is * flagged "export" then it may send an ephemeral * RSA key pair, which will be weak and probably * not very ephemeral, since RSA key pair generation * is kinda expensive. * * Format: modulus, public exponent, signature. */ hm.ReadBlobVar(2); hm.ReadBlobVar(2); if (version >= M.TLSv12) { /* * Hash-and-sign identifiers. */ hm.Read2(); } hm.ReadBlobVar(2); } else if (cs.IsSRP) { /* * SRP parameters are: N, g, s, B. N is the * modulus. */ dhSize = M.BitLength(hm.ReadBlobVar(2)); hm.ReadBlobVar(2); hm.ReadBlobVar(1); hm.ReadBlobVar(2); /* * RFC 5054 says that there is a signature, * except if the server sent no certificate. What * happens at the encoding level is unclear, so * we skip the remaining bytes. */ hm.SkipRemainder(); } else if (cs.IsPSK) { /* * Key hint from the server. */ hm.ReadBlobVar(2); } else { throw new IOException("Unexpected ServerKeyExchange"); } hm.Close(); }
/* * Parse messages from the server: from ServerHello to * ServerHelloDone. */ internal void Parse(SSLRecord rec) { rec.SetExpectedType(M.HANDSHAKE); /* * First parse a ServerHello. */ HMParser sh = new HMParser(rec); if (sh.MessageType != M.SERVER_HELLO) { throw new Exception("Not a ServerHello"); } version = sh.Read2(); byte[] serverRandom = sh.ReadBlobFixed(32); timeMillis = 1000 * (long)M.Dec32be(serverRandom, 0); sessionID = sh.ReadBlobVar(1); if (sessionID.Length > 32) { throw new Exception("Oversized session ID"); } selectedCipherSuite = sh.Read2(); int cm = sh.Read1(); if (cm == 0) { deflateCompress = false; } else if (cm == 1) { deflateCompress = true; } else { throw new Exception( "Unknown compression method: " + cm); } if (!sh.EndOfStruct) { sh.OpenVar(2); Dictionary <int, bool> d = new Dictionary <int, bool>(); while (!sh.EndOfStruct) { int extType = sh.Read2(); if (d.ContainsKey(extType)) { throw new Exception( "Duplicate extension: " + extType); } d[extType] = true; sh.OpenVar(2); switch (extType) { case M.EXT_SERVER_NAME: ParseEmptyServerName(sh); break; case M.EXT_RENEGOTIATION_INFO: ParseRenegInfo(sh); break; case M.EXT_SUPPORTED_CURVES: ParseSupportedCurves(sh); break; case M.EXT_SUPPORTED_EC_POINTS: ParseSupportedECPoints(sh); break; default: throw new Exception( "Unknown extension: " + extType); } sh.Close(); } sh.Close(); } sh.Close(); /* * Read other messages, up to the ServerHelloDone. */ try { bool seenSHD = false; while (!seenSHD) { HMParser hm = new HMParser(rec); switch (hm.MessageType) { case M.CERTIFICATE: ParseCertificate(hm); break; case M.SERVER_KEY_EXCHANGE: ParseServerKeyExchange(hm); break; case M.CERTIFICATE_REQUEST: ParseCertificateRequest(hm); break; case M.SERVER_HELLO_DONE: hm.Close(); seenSHD = true; break; default: hm.Close(true); break; } } } catch { failedAfterHello = true; } recordVersion = rec.GetInVersion(); }