TLS.Mod 63 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839
  1. MODULE TLS; (** AUTHOR "F.N."; PURPOSE "RFC 2246: Transport Layer Security v1.0"; *)
  2. (*
  3. 05.2014 -- Timothée Martiel -- Implemented TLS client connection.
  4. *)
  5. IMPORT
  6. TCP, Streams, Files, IP, KernelLog , Pipes, Kernel, Clock, BIT,
  7. Ciphers := CryptoCiphers, Utils := CryptoUtils, HMAC := CryptoHMAC,
  8. CryptoMD5, CryptoSHA1, CryptoRSA, CryptoBigNumbers, PKCS1, X509;
  9. CONST
  10. (* debugging *)
  11. Trace = TRUE;
  12. (** tlsStates *)
  13. ServerHandshake* = 12;
  14. ClientHandshake* = 13;
  15. (* client and server common handshake states *)
  16. NotAValidHandshakeState = 100; HandshakeFinished = 101; GenerateChangeCipherSpec = 102; AwaitFinished = 103;
  17. (* server-side handshake states *)
  18. AwaitClientHello = 201; GenerateServerHello = 202; GenerateServerHelloDone = 203; AwaitClientKeyExchange = 204;
  19. AwaitChangeSpec = 205; GenerateHelloWithResumption = 210;
  20. AwaitChangeSpecWithResumption = 211; AwaitFinishedWithResumption = 212;
  21. (* client-side handshake states *)
  22. GenerateClientHello = 300; AwaitServerHello = 301; AwaitCertificate = 302; AwaitServerHelloDone = 303; GenerateClientKeyExchange = 304;
  23. (** available cipher suites *)
  24. TlsRsaWithNullMd5* = 0001H; TlsRsaWithNullSha* = 0002H; TlsRsaWithRc4128Md5* = 0004H;
  25. TlsRsaWithRc4128Sha* = 0005H; TlsRsaWithIdeaCbcSha* = 0007H; TlsRsaWithDesCbcSha* = 0009H;
  26. TlsRsaWith3DesEdeCbcSha* = 000AH;
  27. (* not supported
  28. TlsDhDssWithDesCbcSha* = 000CH; TlsDhDssWith3DesEdeCbcSha* = 000DH;
  29. TlsDhRsaWithDesCbcSha* = 000FH; TlsDhRsaWith3DesEdeCbcSha* = 0010H;
  30. TlsDhAnonWithRc4128Md5* = 0018H; TlsDhAnonWithDesCbcSha* = 001AH; TlsDhAnonWith3DesEdeCbcSha* = 001BH;
  31. *)
  32. (* TLS 1.2 cipher suites, not implemented yet *)
  33. (*TlsRsaWithAes128CbcSha* = 002FH;
  34. (* not supported
  35. TlsDhDssWithAes128CbcSha* = 0030H; TlsDhRsaWithAes128CbcSha* = 0031H;
  36. TlsDheDssWithAes128CbcSha* = 0032H; TlsDheRsaWithAes128CbcSha* = 0033H;
  37. TlsDhAnonWithAes128CbcSha* = 0034H;
  38. *)
  39. TlsRsaWithAes256CbcSha* = 0035H;
  40. (* not supported
  41. TlsDhDssWithAes256CbcSha* = 0036H; TlsDhRsaWithAes256CbcSha* = 0037H;
  42. TlsDheDssWithAes256CbcSha* = 0038H; TlsDheRsaWithAes256CbcSha* = 0039H;
  43. TlsDhAnonWithAes256CbcSha* = 003AH;
  44. *)*)
  45. (** record layer content type *)
  46. ChangeCipherSpec* = 20; Alert* = 21; Handshake* = 22; ApplicationData* = 23; SSLv2ClientHello* = 128;
  47. (** handshake message types *)
  48. HelloRequest* = 0; ClientHello* = 1; ServerHello* = 2; Certificate* = 11;
  49. ServerKeyExchange* = 12; CertificateRequest* = 13; ServerHelloDone* = 14; CertificateVerify* = 15;
  50. ClientKeyExchange* = 16; Finished* = 20;
  51. V2ClientHello* = 30;
  52. (* alert levels *)
  53. Warning = 1; Fatal = 2;
  54. (* alert types *)
  55. NoError = -1;
  56. CloseNotify = 0; UnexpectedMessage = 10; BadRecordMac = 20; DecryptionFailed = 21;
  57. RecordOverflow = 22; DecompressionFailure = 30; HandshakeFailure = 40; NoCertificate = 41; (* only SSL 3.0 *)
  58. BadCertificate = 42; UnsupportedCertificate = 43; CertificateRevoked = 44; CertificateExpired = 45;
  59. CertificateUnknown = 46; IllegalParameter = 47; UnknownCA = 48; AccessDenied = 49;
  60. DecodeError = 50; DecryptError = 51; ExportRestriction = 60; ProtocolVersion = 70;
  61. InsufficientSecurity = 71; InternalError = 80; UserCancelled = 90; NoRenegotiation = 100; UnsupportedExtension=110;
  62. (** error numbers *)
  63. Ok* = 0; TLSHandshakeAborted* = 2;
  64. Suites* = 20;
  65. Buflen = 18500;
  66. MaxPHashKernelLogput = 1024;
  67. MaxKeyBlock = 120;
  68. MaxPHashSeed = 128;
  69. MaxPlaintextLength = 16384; (* 2^14 *)
  70. MaxCompressedLength = 17408; (* 2^14 + 2^10 *)
  71. MaxCiphertextLength = 18432; (* 2^14 + 2^11 *)
  72. SessionIdLength = 16;
  73. SessionHashtableSize = 1023; (* 256 * 456 *)
  74. SessionCleanUpInterval = 60; (* seconds *)
  75. DefaultSessionLifetime = 3600; (* seconds *)
  76. DefaultSuitesNbr = 4;
  77. TYPE
  78. SecurityParameters = OBJECT
  79. VAR
  80. cipherSuite, cipherKeySize: LONGINT; (* size in bytes *)
  81. clientRandom, serverRandom: ARRAY 32 OF CHAR;
  82. END SecurityParameters;
  83. ConnectionState = OBJECT
  84. VAR
  85. cipher: Ciphers.Cipher;
  86. mac: HMAC.HMac;
  87. recordSeq: DoubleLong;
  88. cipherKey: ARRAY 24 OF CHAR;
  89. iv: ARRAY 8 OF CHAR;
  90. macSecret: ARRAY 20 OF CHAR;
  91. PROCEDURE & Init*;
  92. BEGIN
  93. NEW( recordSeq)
  94. END Init;
  95. END ConnectionState;
  96. (*
  97. DoubleLong = OBJECT (* 64-bit number, the initial value is -1 *)
  98. VAR num -: ARRAY 2 OF LONGINT; (* 64 bits, msb: num[ 0 ] *)
  99. PROCEDURE & Init*;
  100. BEGIN
  101. num[ 0 ] := 0; num[ 1 ] := -1
  102. END Init;
  103. PROCEDURE Inc;
  104. BEGIN
  105. ASSERT( ( num[ 0 ] < MAX( LONGINT ) ) OR ( num[ 1 ] < MAX( LONGINT ) ) );
  106. IF num[ 1 ] < MAX( LONGINT ) THEN
  107. INC( num[ 1 ] );
  108. RETURN
  109. ELSE
  110. num[ 1 ] := 0;
  111. INC( num[ 0 ] )
  112. END
  113. END Inc;
  114. (* write the current value of num in big-endian to data starting at ofs *)
  115. PROCEDURE GetBytes( VAR data: ARRAY OF CHAR; ofs: LONGINT );
  116. BEGIN
  117. ASSERT( ofs < LEN( data ) - 7 );
  118. data[ ofs ] := CHR( num[ 0 ] DIV ( 256*256*256 ) );
  119. data[ ofs + 1 ] := CHR( num[ 0 ] DIV ( 256*256 ) );
  120. data[ ofs + 2 ] := CHR( num[ 0 ] DIV 256 );
  121. data[ ofs + 3 ] := CHR( num[ 0 ] );
  122. data[ ofs + 4 ] := CHR( num[ 1 ] DIV ( 256*256*256 ) );
  123. data[ ofs + 5 ] := CHR( num[ 1 ] DIV ( 256*256 ) );
  124. data[ ofs + 6 ] := CHR( num[ 1 ] DIV 256 );
  125. data[ ofs + 7 ] := CHR( num[ 1 ] )
  126. END GetBytes;
  127. END DoubleLong;
  128. *) (*! contains a large gap between 80000000 and 100000000. g.f. *)
  129. DoubleLong = OBJECT (* 64-bit counter, the initial value is -1 *)
  130. VAR
  131. numH, numL: LONGINT;
  132. PROCEDURE &Init;
  133. BEGIN
  134. numH := -1; numL := -1
  135. END Init;
  136. PROCEDURE Inc;
  137. BEGIN
  138. IF numL # -1 THEN INC( numL )
  139. ELSIF numH = -1 THEN numH := 0; numL := 0
  140. ELSE INC( numH ); numL := 0
  141. END
  142. END Inc;
  143. (* write the current value of num in big-endian to buf starting at ofs *)
  144. PROCEDURE GetBytes( VAR buf: ARRAY OF CHAR; ofs: LONGINT );
  145. VAR p, val: LONGINT;
  146. BEGIN
  147. p := ofs + 7; val := numL;
  148. REPEAT
  149. buf[p] := CHR( val MOD 256 );
  150. IF p = ofs + 4 THEN val := numH ELSE val := val DIV 256 END;
  151. DEC( p )
  152. UNTIL p < ofs;
  153. END GetBytes;
  154. END DoubleLong;
  155. (* data expansion function as defined in rfc2246, section 5 *)
  156. PHash = OBJECT
  157. VAR hMac: HMAC.HMac;
  158. (* initialization of a PHash object using h as internal hashing-function *)
  159. PROCEDURE & Init*( hashname: ARRAY OF CHAR );
  160. BEGIN
  161. NEW( hMac, hashname );
  162. END Init;
  163. PROCEDURE Expand( VAR secret, seed, outbuf: ARRAY OF CHAR; secretLen, seedLen, outLen: LONGINT );
  164. VAR
  165. a: ARRAY 2 * MaxPHashSeed OF CHAR;
  166. i, iterations: LONGINT;
  167. BEGIN
  168. ASSERT( seedLen <= ( MaxPHashSeed ) );
  169. ASSERT( outLen <= ( MaxPHashKernelLogput ) );
  170. hMac.Initialize( secret, secretLen );
  171. hMac.Update( seed, 0, seedLen );
  172. hMac.GetMac( a, 0 ); (* a( 1 ) *)
  173. FOR i := 0 TO seedLen-1 DO a[ hMac.size + i ] := seed[ i ] END; (* concatenate seed to a( 1 ) *)
  174. iterations := ( outLen DIV hMac.size ) + 1;
  175. (* iteration *)
  176. FOR i := 0 TO iterations - 1 DO
  177. hMac.Initialize( secret, secretLen );
  178. hMac.Update( a, 0, hMac.size+seedLen );
  179. hMac.GetMac( outbuf, i*hMac.size );
  180. (* increment a *)
  181. hMac.Initialize( secret, secretLen );
  182. hMac.Update( a, 0, hMac.size );
  183. hMac.GetMac( a, 0 )
  184. END
  185. END Expand;
  186. END PHash;
  187. (* pseudorandom stream as defined in rfc2246, section 5 *)
  188. PRF = OBJECT
  189. VAR pMD5, pSHA: PHash;
  190. PROCEDURE & Init*;
  191. BEGIN
  192. NEW( pMD5, "CryptoMD5" ); NEW( pSHA, "CryptoSHA1" )
  193. END Init;
  194. PROCEDURE GetBytes( VAR secret, seed, outbuf: ARRAY OF CHAR; label: ARRAY OF CHAR; secretLen, seedLen, outLen: LONGINT );
  195. VAR
  196. md5Result, shaResult: ARRAY MaxKeyBlock OF CHAR;
  197. pSeed, s1, s2: ARRAY 128 OF CHAR;
  198. i, j, l: LONGINT;
  199. BEGIN
  200. (* pseed := label::seed *)
  201. l := LEN( label ) - 1;
  202. FOR i := 0 TO l-1 DO pSeed[ i ] := label[ i ] END;
  203. FOR i := 0 TO seedLen-1 DO pSeed[ l + i ] := seed[ i ] END;
  204. j := secretLen DIV 2 + secretLen MOD 2; (* j := ceil( secretLen / 2 ) *)
  205. FOR i := 0 TO j-1 DO s1[ i ] := secret[ i ] END;
  206. FOR i := secretLen-j TO secretLen-1 DO s2[ i+j-secretLen ] := secret[ i ] END;
  207. pMD5.Expand( s1, pSeed, md5Result, j, seedLen+l, outLen );
  208. pSHA.Expand( s2, pSeed, shaResult, j, seedLen+l, outLen );
  209. FOR i := 0 TO outLen-1 DO outbuf[ i ] := BIT.CXOR( md5Result[ i ], shaResult[ i ] ) END
  210. END GetBytes;
  211. END PRF;
  212. Policy* = OBJECT
  213. VAR
  214. cipherSuites -: ARRAY Suites OF LONGINT;
  215. nofCipherSuites -: LONGINT; (** number of enabled cipher-suites *)
  216. sessionResumptionEnabled -: BOOLEAN;
  217. sessionLifetime -: LONGINT; (** seconds *)
  218. PROCEDURE &Init*;
  219. BEGIN
  220. (* set default values *)
  221. sessionResumptionEnabled := TRUE;
  222. sessionLifetime := DefaultSessionLifetime
  223. END Init;
  224. (** set n negotiable cipher suites in order of preference*)
  225. PROCEDURE SetCipherSuites*( VAR s: ARRAY OF LONGINT; n: LONGINT );
  226. VAR i: LONGINT;
  227. BEGIN
  228. ASSERT( n <= Suites );
  229. FOR i := 0 TO n-1 DO cipherSuites[ i ] := s[ i ] END;
  230. nofCipherSuites := n
  231. END SetCipherSuites;
  232. (** Returns TRUE if the cipher-suite s is supported by this policy *)
  233. PROCEDURE IsSupported*( s: LONGINT ): BOOLEAN;
  234. VAR i: LONGINT;
  235. BEGIN
  236. FOR i := 0 TO nofCipherSuites - 1 DO
  237. IF cipherSuites[ i ] = s THEN RETURN TRUE END
  238. END;
  239. RETURN FALSE
  240. END IsSupported;
  241. (** set whether sessions may be resumed; default is TRUE *)
  242. PROCEDURE EnableSessionResumption*( enable: BOOLEAN );
  243. BEGIN sessionResumptionEnabled := enable
  244. END EnableSessionResumption;
  245. (** lifetime of a session in seconds; default: 3600s *)
  246. PROCEDURE SetSessionLifetime*( t: LONGINT );
  247. BEGIN
  248. ASSERT( t >= 0 );
  249. sessionLifetime := t
  250. END SetSessionLifetime;
  251. END Policy;
  252. Session = OBJECT
  253. VAR
  254. id : ARRAY 32 OF CHAR;
  255. idLength : LONGINT;
  256. resumable : BOOLEAN;
  257. cipherSuite : LONGINT;
  258. preMasterSecret, masterSecret -: ARRAY 48 OF CHAR;
  259. lifetime: LONGINT; (* seconds *)
  260. timer: Kernel.Timer;
  261. next: Session;
  262. (** initialize a session.
  263. If caching is FALSE, no session-id will associated with the new session.
  264. if cache is TRUE and len is zero, a session id will be randomly generated.
  265. if cache is TRUE and len is non-zero, a session-id will be read from data *)
  266. PROCEDURE & Init*( caching: BOOLEAN; VAR data: ARRAY OF CHAR; ofs, len, lifetime: LONGINT );
  267. VAR i: LONGINT;
  268. BEGIN
  269. ASSERT( ofs > -1 ); ASSERT( len > -1 ); ASSERT( ofs + len <= LEN( data ) ); ASSERT( lifetime > 0 );
  270. resumable := caching;
  271. IF caching THEN
  272. IF len = 0 THEN (* server-side: session-id has to be generated *)
  273. idLength := SessionIdLength;
  274. Utils.RandomBytes( id, 0, SessionIdLength )
  275. ELSE (* client-side: session-id has been generated by server *)
  276. idLength := len;
  277. FOR i := 0 TO len - 1 DO id[ i ] := data[ ofs + i ] END
  278. END
  279. END;
  280. cipherSuite := 0;
  281. SELF.lifetime := lifetime
  282. END Init;
  283. (** Marks this Session as not resumable for future Connections *)
  284. PROCEDURE Invalidate;
  285. BEGIN
  286. resumable := FALSE
  287. END Invalidate;
  288. (** Sets the PreMasterSecret contained in data, starting at ofs. The lenght of the PreMasterSecret is always 48 bytes *)
  289. PROCEDURE SetPreMasterSecret( data: ARRAY OF CHAR; ofs: LONGINT );
  290. VAR i: LONGINT;
  291. BEGIN
  292. ASSERT( LEN(data) >= ofs + 48 );
  293. FOR i := 0 TO 47 DO preMasterSecret[ i ] := data[ ofs + i ] END
  294. END SetPreMasterSecret;
  295. BEGIN { ACTIVE }
  296. NEW( timer );
  297. timer.Sleep( 1000 * lifetime );
  298. Invalidate( )
  299. END Session;
  300. Context* = OBJECT
  301. VAR
  302. policy-: Policy;
  303. rsaCertificate: ARRAY 10000 OF CHAR;
  304. rsaPrivateKey, rsaPublicKey: CryptoRSA.Key;
  305. lengthOfRsaCertificate: LONGINT;
  306. sessionCache: ARRAY SessionHashtableSize OF Session;
  307. timer: Kernel.Timer;
  308. active: BOOLEAN;
  309. PROCEDURE & Init*( p: Policy );
  310. BEGIN
  311. policy := p;
  312. NEW( timer );
  313. active := TRUE
  314. END Init;
  315. PROCEDURE Dispose*;
  316. BEGIN
  317. active := FALSE
  318. END Dispose;
  319. (** Loads the rsa-certificate specified with filename. The certificate must be DER-formatted *)
  320. PROCEDURE LoadRsaCertificate*( filename: ARRAY OF CHAR ): LONGINT;
  321. VAR
  322. f: Files.File;
  323. r: Files.Reader;
  324. i: LONGINT;
  325. BEGIN
  326. f := Files.Old(filename); (* open an old file *)
  327. IF f # NIL THEN
  328. Files.OpenReader( r, f, 0); (* open a buffer on the file *)
  329. i := 0;
  330. WHILE r.res # Streams.EOF DO
  331. rsaCertificate[ i + 6 ] := r.Get( ); (* first six bytes are length-fields of the certificate *)
  332. INC( i )
  333. END;
  334. lengthOfRsaCertificate := i-1;
  335. IF Trace THEN PrintRsaCertificate( ) END;
  336. (* length-fields *)
  337. rsaCertificate[ 0 ] := CHR( ( lengthOfRsaCertificate + 3 ) DIV ( 256 * 256 ) );
  338. rsaCertificate[ 1 ] := CHR( ( lengthOfRsaCertificate + 3 ) DIV 256 MOD 256 );
  339. rsaCertificate[ 2 ] := CHR( ( lengthOfRsaCertificate + 3 ) MOD 256 );
  340. rsaCertificate[ 3 ] := CHR( ( lengthOfRsaCertificate ) DIV ( 256 * 256 ) );
  341. rsaCertificate[ 4 ] := CHR( ( lengthOfRsaCertificate ) DIV 256 MOD 256 );
  342. rsaCertificate[ 5 ] := CHR( ( lengthOfRsaCertificate ) MOD 256 );
  343. INC( lengthOfRsaCertificate, 6 );
  344. RETURN Ok
  345. ELSE
  346. KernelLog.String("RSA Certificate file not found"); KernelLog.Ln;
  347. RETURN -1;
  348. END
  349. END LoadRsaCertificate;
  350. (** Loads the material needed to establish an rsa private key. Parameters p and q are two big prime numbers,
  351. e is the public exponent of the public key of the rsa certificate to be used. p, q and e have to be hexadecimal strings.
  352. pLen, qLen and eLen are the lengths of the hex strings *)
  353. PROCEDURE LoadRsaPrivateKey*( pHex, qHex, eHex: ARRAY OF CHAR; pLen, qLen, eLen: INTEGER );
  354. VAR
  355. p, q, e: CryptoBigNumbers.BigNumber;
  356. dummy: CryptoRSA.Key;
  357. BEGIN
  358. CryptoBigNumbers.AssignHex( p, pHex, pLen );
  359. CryptoBigNumbers.AssignHex( q, qHex, qLen );
  360. CryptoBigNumbers.AssignHex( e, eHex, eLen );
  361. NEW( SELF.rsaPrivateKey ); NEW( dummy );
  362. CryptoRSA.MakeKeys( p, q, e, "AosTLS", dummy, SELF.rsaPrivateKey );
  363. IF Trace THEN
  364. KernelLog.String("RSA-key loaded"); KernelLog.Ln;
  365. KernelLog.String(" prime p:"); KernelLog.Ln;
  366. CryptoBigNumbers.Print( p );
  367. KernelLog.String(" prime q:"); KernelLog.Ln;
  368. CryptoBigNumbers.Print( q );
  369. KernelLog.String(" public exponent:"); KernelLog.Ln;
  370. CryptoBigNumbers.Print( e );
  371. KernelLog.String(" modulus:"); KernelLog.Ln;
  372. CryptoBigNumbers.Print( SELF.rsaPrivateKey.modulus );
  373. KernelLog.String(" private exponent:"); KernelLog.Ln;
  374. CryptoBigNumbers.Print( SELF.rsaPrivateKey.exponent );
  375. END
  376. END LoadRsaPrivateKey;
  377. (** Fills rsaPublicKey from server certificate. *)
  378. PROCEDURE GetRsaPublicKey*;
  379. VAR
  380. certificate: X509.Certificate;
  381. reader: Streams.StringReader;
  382. algorithm: POINTER TO ARRAY OF CHAR;
  383. e, m: CryptoBigNumbers.BigNumber;
  384. writer: Streams.StringWriter;
  385. print: ARRAY 10 * 1024 OF CHAR;
  386. BEGIN
  387. IF rsaPublicKey = NIL THEN
  388. (* Read X509 Certificate *)
  389. NEW(certificate);
  390. NEW(reader, lengthOfRsaCertificate);
  391. (* Skip 6 bytes: they represent the length of the certificate, but are not part of it. *)
  392. reader.SetRaw(rsaCertificate, 6, lengthOfRsaCertificate);
  393. certificate.Read(reader);
  394. (* Get modulus and exponent of public key *)
  395. rsaPublicKey := certificate.publicKey;
  396. END
  397. END GetRsaPublicKey;
  398. PROCEDURE PrintRsaCertificate*;
  399. BEGIN
  400. KernelLog.String("Certificate [");KernelLog.Int(lengthOfRsaCertificate,3);KernelLog.String("]");KernelLog.Ln;
  401. KernelLog.Buffer(rsaCertificate, 6, lengthOfRsaCertificate )
  402. END PrintRsaCertificate;
  403. (** A new server-side Session-object is created and returned according to the policy settings *)
  404. PROCEDURE GetNewServerSession*( ): Session;
  405. VAR
  406. dummy: ARRAY 1 OF CHAR;
  407. s: Session;
  408. BEGIN
  409. NEW( s, policy.sessionResumptionEnabled, dummy, 0, 0, policy.sessionLifetime );
  410. RETURN s
  411. END GetNewServerSession;
  412. (** look up the session cache for a stored cache associated with the session-id of length len,
  413. starting at ofs in data. If no session is found, NIL is returned. This method is invoked by a TLS-server. *)
  414. PROCEDURE FindSessionByID*( VAR data: ARRAY OF CHAR; ofs, idLen: LONGINT ): Session;
  415. VAR
  416. i: LONGINT;
  417. current, previous: Session; (* fork search *)
  418. BEGIN
  419. ASSERT( idLen = SessionIdLength );
  420. ASSERT( idLen < 33 ); ASSERT( idLen >= 2 ); ASSERT( ofs > -1 ); ASSERT( LEN( data ) >= ofs + idLen );
  421. IF ~policy.sessionResumptionEnabled THEN RETURN NIL END;
  422. i := ( ORD( data[ ofs ] ) + 256 * ORD( data[ ofs + 1 ] ) ) MOD SessionHashtableSize;
  423. current := sessionCache[ i ];
  424. previous := sessionCache[ i ];
  425. WHILE current # NIL DO
  426. IF EqualSessionID( current.id, data, 0, ofs, idLen ) THEN
  427. IF current.resumable THEN
  428. IF current # previous THEN (* if current is NOT the first element in the list *)
  429. previous.next := current.next;
  430. current.next := sessionCache[ i ];
  431. sessionCache[ i ] := current
  432. END;
  433. RETURN current
  434. ELSE
  435. RETURN NIL
  436. END
  437. ELSE
  438. previous := current;
  439. current := current.next
  440. END
  441. END;
  442. RETURN NIL
  443. END FindSessionByID;
  444. (* stores a given Session-object in the session-cache *)
  445. PROCEDURE StoreSession( s: Session );
  446. VAR i: LONGINT;
  447. BEGIN
  448. ASSERT( s.resumable );
  449. i := ORD( s.id[ 0 ] ) + 256 * ORD( s.id[ 1 ] );
  450. i := i MOD SessionHashtableSize;
  451. s.next := sessionCache[ i ];
  452. sessionCache[ i ] := s
  453. END StoreSession;
  454. (* returns TRUE iff data1 and data2 contain the same string of length len starting at different offsets *)
  455. PROCEDURE EqualSessionID( VAR data1, data2: ARRAY OF CHAR; ofs1, ofs2, len: LONGINT ): BOOLEAN;
  456. VAR i: LONGINT;
  457. BEGIN
  458. FOR i := 0 TO len - 1 DO
  459. IF data1[ ofs1 + i ] # data2[ ofs2 + i ] THEN RETURN FALSE END;
  460. END;
  461. RETURN TRUE
  462. END EqualSessionID;
  463. (* recursive function *)
  464. PROCEDURE DeleteUnresumableSessions( s: Session ): Session;
  465. BEGIN
  466. IF s = NIL THEN RETURN NIL END; (* end of recursion *)
  467. IF s.resumable THEN
  468. s.next := DeleteUnresumableSessions( s.next );
  469. RETURN s
  470. ELSE
  471. RETURN DeleteUnresumableSessions( s.next )
  472. END
  473. END DeleteUnresumableSessions;
  474. (* delete unresumable sessions *)
  475. PROCEDURE CleanUpSessionCache;
  476. VAR i: LONGINT;
  477. BEGIN
  478. FOR i := 0 TO SessionHashtableSize - 1 DO
  479. sessionCache[ i ] := DeleteUnresumableSessions( sessionCache[ i ] )
  480. END
  481. END CleanUpSessionCache;
  482. BEGIN { ACTIVE }
  483. WHILE active DO
  484. timer.Sleep( SessionCleanUpInterval * 1000 );
  485. CleanUpSessionCache( )
  486. END
  487. END Context;
  488. Connection* = OBJECT ( TCP.Connection )
  489. VAR
  490. conn: TCP.Connection;
  491. in: Streams.Reader;
  492. out, appDataWriter: Streams.Writer;
  493. appDataReader: Streams.Reader;
  494. applicationDataPipe: Pipes.Pipe;
  495. context: Context;
  496. session: Session;
  497. tlsErrorCause -: LONGINT; (** alert type that lead to failure *)
  498. handshakeState: LONGINT;
  499. outbuf, inbuf: ARRAY Buflen OF CHAR; (* buffers for outgoing and incoming messages *)
  500. hsMD5send, hsMD5verify: CryptoMD5.Hash; (* handshake hash functions; to be used in the Finished messages *)
  501. hsSHAsend, hsSHAverify: CryptoSHA1.Hash; (* handshake hash functions; to be used in the Finished messages *)
  502. pendingSecurityParameters: SecurityParameters;
  503. currentWriteState, pendingWriteState, currentReadState, pendingReadState: ConnectionState;
  504. client: BOOLEAN;
  505. PROCEDURE &Init*;
  506. BEGIN
  507. state := TCP.Unused;
  508. tlsErrorCause := NoError;
  509. (* establish application-data-out-buffer *)
  510. NEW( applicationDataPipe, 1024 * 1024(*4096*) ); (* is this a good size? *)
  511. (*Streams.OpenWriter( appDataWriter, applicationDataPipe.Send );*)
  512. NEW(appDataWriter, applicationDataPipe.Send, 1024*1024);
  513. Streams.OpenReader( appDataReader, applicationDataPipe.Receive );
  514. NEW( hsMD5send ); NEW( hsSHAsend );
  515. NEW( hsMD5verify ); NEW( hsSHAverify );
  516. NEW( pendingWriteState ); NEW( currentWriteState );
  517. NEW( pendingReadState ); NEW( currentReadState );
  518. NEW( pendingSecurityParameters );
  519. hsMD5send.Initialize( ); hsSHAsend.Initialize( );
  520. hsMD5verify.Initialize( ); hsSHAverify.Initialize( )
  521. END Init;
  522. PROCEDURE AwaitStateNotEqual*(s : LONGINT);
  523. BEGIN { EXCLUSIVE}
  524. AWAIT(state # s);
  525. END AwaitStateNotEqual;
  526. PROCEDURE AwaitStateEqual*(s : LONGINT);
  527. BEGIN { EXCLUSIVE}
  528. AWAIT(state = s);
  529. END AwaitStateEqual;
  530. PROCEDURE SetState*(s : SHORTINT);
  531. BEGIN { EXCLUSIVE}
  532. state := s;
  533. END SetState;
  534. PROCEDURE ChangeWriteState;
  535. BEGIN
  536. currentWriteState := pendingWriteState;
  537. NEW( pendingWriteState )
  538. END ChangeWriteState;
  539. PROCEDURE ChangeReadState;
  540. BEGIN
  541. currentReadState := pendingReadState;
  542. NEW( pendingReadState )
  543. END ChangeReadState;
  544. (** Must be called before Open *)
  545. PROCEDURE SetContext*( cxt: Context );
  546. BEGIN
  547. ASSERT( conn = NIL );
  548. context := cxt
  549. END SetContext;
  550. (** open a TLS connection (only use once per Connection instance). Use IP.NilPort for lport to automatically assign
  551. an unused local port. Use IP.NilAdr for fip to open a passive connection. *)
  552. PROCEDURE Open*( lport: LONGINT; fip: IP.Adr; fport: LONGINT; VAR res: LONGINT );
  553. BEGIN
  554. (*ASSERT( IP.IsNilAdr(fip) ); (* only server-side is implemented *)*)
  555. (*ASSERT( context # NIL );*) (* context must be set before calling Open *)
  556. ASSERT( conn = NIL ); (* invoke this method only once per instance *)
  557. IF context=NIL THEN
  558. SetDefaultPolicy
  559. END;
  560. client := ~IP.IsNilAdr(fip);
  561. (* open TCPConnection *)
  562. NEW( SELF.conn );
  563. SELF.conn.Open( lport, fip, fport, res );
  564. IF res # TCP.Ok THEN RETURN END;
  565. SetState(conn.state);
  566. res := Ok;
  567. IF client THEN Connect END;
  568. ASSERT( conn # NIL )
  569. END Open;
  570. PROCEDURE SetDefaultPolicy*;
  571. VAR ctx:Context;
  572. BEGIN
  573. NEW(ctx, defaultCipherPolicy);
  574. SetContext(ctx);
  575. END SetDefaultPolicy;
  576. (* set a TCP Connection for communication; this method should only be invoked by the Accept-method *)
  577. PROCEDURE SetConnection*( c: TCP.Connection );
  578. BEGIN
  579. ASSERT( conn = NIL ); ASSERT( State()= TCP.Unused );
  580. conn := c;
  581. Streams.OpenReader( in, SELF.conn.Receive ); Streams.OpenWriter( out, SELF.conn.Send );
  582. SetState(ServerHandshake);
  583. handshakeState := AwaitClientHello
  584. END SetConnection;
  585. (** Call this method only on a passive (listenig server-side) TLS.Connection. Non blocking *)
  586. PROCEDURE Accept*( VAR client: TCP.Connection; VAR res: LONGINT );
  587. VAR
  588. newTLSConn: Connection;
  589. newTCPConn: TCP.Connection;
  590. BEGIN
  591. ASSERT( State() = TCP.Listen );
  592. ASSERT ( SELF.conn # NIL );
  593. SELF.conn.Accept( newTCPConn, res );
  594. IF res # TCP.Ok THEN RETURN END;
  595. NEW( newTLSConn );
  596. newTLSConn.SetContext( SELF.context );
  597. newTLSConn.SetConnection( newTCPConn );
  598. client := newTLSConn;
  599. res := Ok
  600. END Accept;
  601. (** Sets up the TCP connection for a client-side connection. *)
  602. PROCEDURE Connect*;
  603. BEGIN
  604. Streams.OpenReader( in, SELF.conn.Receive );
  605. Streams.OpenWriter( out, SELF.conn.Send );
  606. SetState(ClientHandshake);
  607. handshakeState := GenerateClientHello
  608. END Connect;
  609. (** Close this TLS.Connection *)
  610. PROCEDURE Close*;
  611. BEGIN
  612. IF Trace THEN KernelLog.String("Close"); KernelLog.Ln; END;
  613. ASSERT( SELF.conn # NIL );
  614. IF ( State() = TCP.Established ) OR ( State() = ServerHandshake ) THEN
  615. SendWarning( CloseNotify )
  616. END;
  617. conn.Close();
  618. applicationDataPipe.Close();
  619. handshakeState := NotAValidHandshakeState;
  620. SetState(TCP.Closed);
  621. END Close;
  622. (** Send secured data *)
  623. PROCEDURE Send*( CONST data: ARRAY OF CHAR; ofs, len: LONGINT; propagate: BOOLEAN; VAR res: LONGINT );
  624. VAR i, size: LONGINT;
  625. BEGIN {EXCLUSIVE}
  626. AWAIT((state = TCP.Established) OR (state = TCP.Closed));
  627. IF state = TCP.Established THEN
  628. WHILE len > 0 DO
  629. IF Trace THEN PrintDirection(TRUE); KernelLog.String("Application Data");KernelLog.Ln END;
  630. size := len;
  631. IF size > MaxPlaintextLength THEN size := MaxPlaintextLength END;
  632. FOR i := 0 TO size-1 DO
  633. outbuf[ i ] := data[ ofs + i ]
  634. END;
  635. SendRecord( outbuf, ApplicationData, 0, size );
  636. INC( ofs, size );
  637. DEC( len, size )
  638. END
  639. ELSE
  640. res := Streams.EOF;
  641. END;
  642. END Send;
  643. (** Receive secured data *)
  644. PROCEDURE Receive*( VAR data: ARRAY OF CHAR; ofs, size, min: LONGINT; VAR len, res: LONGINT );
  645. BEGIN
  646. applicationDataPipe.Receive(data, ofs, size, min, len ,res);
  647. END Receive;
  648. (* Generates the MasterSecret for the current session as described in rfc 2246, section 8 *)
  649. PROCEDURE GenerateMasterSecret;
  650. VAR
  651. prf: PRF;
  652. seed: ARRAY 64 OF CHAR;
  653. i: LONGINT;
  654. BEGIN
  655. FOR i := 0 TO 31 DO
  656. seed[ i ] := SELF.pendingSecurityParameters.clientRandom[ i ];
  657. seed[ i + 32 ] := SELF.pendingSecurityParameters.serverRandom[ i ]
  658. END;
  659. NEW( prf );
  660. prf.GetBytes( SELF.session.preMasterSecret, seed, SELF.session.masterSecret, "master secret", 48, 64, 48 );
  661. (* discard preMasterSecret *)
  662. FOR i := 0 TO 47 DO SELF.session.preMasterSecret[ i ] := CHR( 0 ) END
  663. END GenerateMasterSecret;
  664. (* Generates key-material for the pending state *)
  665. PROCEDURE GenerateKeys;
  666. VAR
  667. prf: PRF;
  668. keyBlock: ARRAY 104 OF CHAR;
  669. seed: ARRAY 64 OF CHAR;
  670. i, keyBlockLen, ofs, macSecretSize, cipherKeySize, cipherBlockSize: LONGINT;
  671. BEGIN
  672. (* calculate the needed amount of key-material *)
  673. macSecretSize := SELF.pendingWriteState.mac.size;
  674. cipherKeySize := SELF.pendingSecurityParameters.cipherKeySize;
  675. IF SELF.pendingWriteState.cipher # NIL THEN
  676. cipherBlockSize := SELF.pendingWriteState.cipher.blockSize
  677. ELSE
  678. cipherBlockSize := 0
  679. END;
  680. keyBlockLen := 2 * macSecretSize + 2 * cipherKeySize;
  681. IF cipherBlockSize > 1 THEN (* if a blockcipher is used, initialization vectors are needed *)
  682. INC( keyBlockLen, 2 * cipherBlockSize )
  683. END;
  684. ASSERT( keyBlockLen <= 104 ); (* 3DES-EDE-CBC-SHA needs 104 bytes of keymaterial. all others need less *)
  685. FOR i := 0 TO 31 DO
  686. seed[ i ] := SELF.pendingSecurityParameters.serverRandom[ i ];
  687. seed[ i + 32 ] := SELF.pendingSecurityParameters.clientRandom[ i ]
  688. END;
  689. NEW( prf );
  690. prf.GetBytes( SELF.session.masterSecret, seed, keyBlock, "key expansion", 48, 64, keyBlockLen );
  691. (* mac secret *)
  692. FOR i := 0 TO macSecretSize - 1 DO
  693. IF client THEN
  694. SELF.pendingWriteState.macSecret[ i ] := keyBlock[ i ];
  695. SELF.pendingReadState.macSecret[ i ] := keyBlock[ macSecretSize + i ]
  696. ELSE
  697. SELF.pendingReadState.macSecret[ i ] := keyBlock[ i ];
  698. SELF.pendingWriteState.macSecret[ i ] := keyBlock[ macSecretSize + i ]
  699. END
  700. END;
  701. (* keys for encryption and decription *)
  702. ofs := 2 * macSecretSize;
  703. FOR i := 0 TO cipherKeySize - 1 DO
  704. IF client THEN
  705. SELF.pendingWriteState.cipherKey[ i ] := keyBlock[ ofs + i ];
  706. SELF.pendingReadState.cipherKey[ i ] := keyBlock[ ofs + cipherKeySize + i ]
  707. ELSE
  708. SELF.pendingReadState.cipherKey[ i ] := keyBlock[ ofs + i ];
  709. SELF.pendingWriteState.cipherKey[ i ] := keyBlock[ ofs + cipherKeySize + i ]
  710. END
  711. END;
  712. (* initialization vectors *)
  713. IF cipherBlockSize > 1 THEN
  714. ofs := 2 * macSecretSize + 2 * cipherKeySize;
  715. FOR i := 0 TO cipherBlockSize - 1 DO
  716. IF client THEN
  717. SELF.pendingWriteState.iv[ i ] := keyBlock[ ofs + i ];
  718. SELF.pendingReadState.iv[ i ] := keyBlock[ ofs + cipherBlockSize + i ]
  719. ELSE
  720. SELF.pendingReadState.iv[ i ] := keyBlock[ ofs + i ];
  721. SELF.pendingWriteState.iv[ i ] := keyBlock[ ofs + cipherBlockSize + i ]
  722. END
  723. END
  724. END
  725. END GenerateKeys;
  726. (* initializes a given ConnectionState with the key material contained in the ConnectionState and in
  727. the given SecurityParameters *)
  728. PROCEDURE InitializeConnectionState( state: ConnectionState; sp: SecurityParameters );
  729. BEGIN
  730. IF state.cipher # NIL THEN
  731. state.cipher.InitKey( state.cipherKey, 8 * sp.cipherKeySize );
  732. IF state.cipher.blockSize > 0 THEN
  733. state.cipher.SetIV( state.iv, Ciphers.CBC )
  734. END
  735. END
  736. END InitializeConnectionState;
  737. PROCEDURE PrepareConnectionState( state: ConnectionState; cipherSuite: LONGINT ; VAR res : LONGINT);
  738. BEGIN
  739. ASSERT( cipherSuite # 0 );
  740. res := Ok;
  741. CASE cipherSuite OF
  742. | TlsRsaWithNullMd5:
  743. NEW( state.mac, "CryptoMD5" );
  744. state.cipher := NIL;
  745. | TlsRsaWithNullSha:
  746. NEW( state.mac, "CryptoSHA1" );
  747. state.cipher := NIL;
  748. | TlsRsaWithRc4128Md5:
  749. NEW( state.mac, "CryptoMD5" );
  750. state.cipher := Ciphers.NewCipher( "CryptoARC4" );
  751. | TlsRsaWithRc4128Sha:
  752. NEW( state.mac, "CryptoSHA1" );
  753. state.cipher := Ciphers.NewCipher( "CryptoARC4" );
  754. | TlsRsaWithIdeaCbcSha:
  755. NEW( state.mac, "CryptoSHA1" );
  756. state.cipher := Ciphers.NewCipher( "CryptoIDEA" );
  757. | TlsRsaWithDesCbcSha:
  758. NEW( state.mac, "CryptoSHA1" );
  759. state.cipher := Ciphers.NewCipher( "CryptoDES" );
  760. | TlsRsaWith3DesEdeCbcSha:
  761. NEW( state.mac, "CryptoSHA1" );
  762. state.cipher := Ciphers.NewCipher( "CryptoDES3" );
  763. ELSE
  764. res := -1;
  765. END;
  766. END PrepareConnectionState;
  767. PROCEDURE PrepareSecurityParameters( sp: SecurityParameters; cipherSuite: LONGINT ; VAR res : LONGINT);
  768. BEGIN
  769. ASSERT( cipherSuite # 0 );
  770. res := Ok;
  771. sp.cipherSuite := cipherSuite;
  772. CASE cipherSuite OF
  773. | TlsRsaWithNullMd5:
  774. sp.cipherKeySize := 0;
  775. | TlsRsaWithNullSha:
  776. sp.cipherKeySize := 0;
  777. | TlsRsaWithRc4128Md5:
  778. sp.cipherKeySize := 16;
  779. | TlsRsaWithRc4128Sha:
  780. sp.cipherKeySize := 16;
  781. | TlsRsaWithIdeaCbcSha:
  782. sp.cipherKeySize := 16;
  783. | TlsRsaWithDesCbcSha:
  784. sp.cipherKeySize := 8;
  785. | TlsRsaWith3DesEdeCbcSha:
  786. sp.cipherKeySize := 24;
  787. ELSE
  788. res := -1
  789. END;
  790. END PrepareSecurityParameters;
  791. (* **********************************************************************************
  792. RECORD LAYER
  793. ********************************************************************************** *)
  794. PROCEDURE SendRecord( VAR data: ARRAY OF CHAR; contentType, ofs, len: LONGINT );
  795. VAR
  796. macInput: ARRAY 13 OF CHAR;
  797. i, length, padLen, blocksize: LONGINT;
  798. t: LONGINT;
  799. BEGIN
  800. ASSERT( len <= MaxPlaintextLength );
  801. (* increment the number of sent records *)
  802. currentWriteState.recordSeq.Inc( );
  803. length := len;
  804. (* data compression: no other algo than NULL is implemented *)
  805. (* mac *)
  806. IF currentWriteState.mac # NIL THEN
  807. currentWriteState.recordSeq.GetBytes( macInput, 0 );
  808. macInput[ 8 ] := CHR( contentType );
  809. macInput[ 9 ] := version[ 0 ];
  810. macInput[ 10 ] := version[ 1 ];
  811. macInput[ 11 ] := CHR( len DIV 256 );
  812. macInput[ 12 ] := CHR( len );
  813. currentWriteState.mac.Initialize( currentWriteState.macSecret, currentWriteState.mac.size );
  814. currentWriteState.mac.Update( macInput, 0, 13 );
  815. currentWriteState.mac.Update( data, ofs, len );
  816. currentWriteState.mac.GetMac( data, ofs+len );
  817. INC( length, currentWriteState.mac.size )
  818. END;
  819. (* encryption *)
  820. IF currentWriteState.cipher # NIL THEN (* encryption has to be done *)
  821. blocksize := currentWriteState.cipher.blockSize;
  822. IF blocksize > 1 THEN (* padding for encryption has to be added *)
  823. padLen := ( blocksize - ( ( length + 1 ) MOD blocksize ) ) MOD blocksize; (* padLen = [ 0, blocksize-1 ] *)
  824. IF padLen > 0 THEN
  825. FOR i := 0 TO padLen - 1 DO data[ ofs + length + i ] := CHR( padLen ) END
  826. END;
  827. data[ ofs + length + padLen ] := CHR( padLen );
  828. length := length + padLen + 1
  829. END;
  830. currentWriteState.cipher.Encrypt( data, ofs, length );
  831. END;
  832. (* record header *)
  833. out.Char( CHR( contentType ) );
  834. out.Char( CHR( 3 ) );
  835. out.Char( CHR( 1 ) );
  836. out.Char( CHR( length DIV 256 ) );
  837. out.Char( CHR( length ) );
  838. out.Bytes( data, ofs, length );
  839. out.Update;
  840. END SendRecord;
  841. (* receive one record *)
  842. PROCEDURE ReceiveRecord;
  843. VAR
  844. macInput: ARRAY 13 OF CHAR;
  845. verify: ARRAY 20 OF CHAR;
  846. i, length, len, type, macSize, res, major, minor: LONGINT;
  847. tt: LONGINT;
  848. BEGIN
  849. (* increment the number of received records *)
  850. currentReadState.recordSeq.Inc( );
  851. (* record header *)
  852. type := ORD( in.Get( ) ); (* content type *)
  853. IF type = 128 THEN (* SSLv2-compatible ClientHello *)
  854. len := ORD( in.Get() );
  855. in.Bytes( inbuf, 0, len, length );
  856. IF len = length THEN
  857. ReceiveV2Handshake( inbuf, 0, len );
  858. RETURN
  859. ELSE
  860. SendError( InternalError );
  861. RETURN
  862. END
  863. END;
  864. major := ORD( in.Get() ); minor := ORD( in.Get() );
  865. IF ( major # 3 ) OR ( minor # 1) THEN END; (* version control *)
  866. len := 256 * ORD( in.Get() ) + ORD( in.Get() ); (* length of payload *)
  867. IF len > MaxCiphertextLength THEN
  868. SendError( RecordOverflow );
  869. RETURN
  870. END;
  871. (* payload *)
  872. in.Bytes( inbuf, 0, len, length );
  873. IF in.res # Streams.Ok THEN
  874. IF Trace THEN KernelLog.String("Can't read record: supposed to read:"); KernelLog.Int(len, 7); KernelLog.String(" read: "); KernelLog.Int(length,7);END;
  875. RETURN
  876. END;
  877. (* records with unknown client protocol type are ignored; type=128: SSLv2-compatible ClientHello *)
  878. IF ( type = 128 ) OR ( type < 20 ) OR ( type > 23 ) THEN RETURN END;
  879. IF length # len THEN
  880. SendError( IllegalParameter );
  881. RETURN
  882. END;
  883. (* decryption *)
  884. IF currentReadState.cipher # NIL THEN
  885. currentReadState.cipher.Decrypt( inbuf, 0, len );
  886. IF res # Ciphers.Ok THEN
  887. IF Trace THEN KernelLog.String("There was a Problem while decrypting record.");KernelLog.Ln END;
  888. SendError( InternalError );
  889. RETURN
  890. END;
  891. IF currentReadState.cipher.blockSize > 1 THEN (* padding has to be removed *)
  892. len := len - ORD( inbuf[ len ] ) - 1;
  893. END
  894. END;
  895. (* mac verification *)
  896. IF currentReadState.mac # NIL THEN
  897. macSize := currentReadState.mac.size;
  898. len := len - macSize;
  899. currentReadState.recordSeq.GetBytes( macInput, 0 );
  900. macInput[ 8 ] := CHR( type );
  901. macInput[ 9 ] := CHR( major );
  902. macInput[ 10 ] := CHR( minor );
  903. macInput[ 11 ] := CHR( len DIV 256 );
  904. macInput[ 12 ] := CHR( len );
  905. currentReadState.mac.Initialize( currentReadState.macSecret, macSize );
  906. currentReadState.mac.Update( macInput, 0, 13 );
  907. currentReadState.mac.Update( inbuf, 0, len );
  908. currentReadState.mac.GetMac( verify, 0 );
  909. FOR i := 0 TO macSize - 1 DO
  910. IF inbuf[ len + i ] # verify[ i ] THEN
  911. SendError( BadRecordMac );
  912. RETURN
  913. END
  914. END
  915. END;
  916. (* data compression: no other algo than NULL is implemented *)
  917. (* dispatching *)
  918. CASE type OF
  919. | Handshake:
  920. ReceiveHandshake( inbuf, 0, len )
  921. | ApplicationData:
  922. appDataWriter.Bytes( inbuf, 0, len );
  923. appDataWriter.Update;
  924. | Alert:
  925. ASSERT( len = 2 );
  926. ReceiveAlert( inbuf, 0, len )
  927. | ChangeCipherSpec:
  928. ASSERT( len = 1 );
  929. Transition( inbuf, ChangeCipherSpec, 0, 0, len )
  930. END;
  931. END ReceiveRecord;
  932. (* **********************************************************************************
  933. CHANGE CIPHER SPEC PROTOCOL
  934. ********************************************************************************** *)
  935. PROCEDURE SendChangeCipherSpec;
  936. BEGIN
  937. IF Trace THEN PrintDirection(TRUE); KernelLog.String("ChangeCipherSpec: ");KernelLog.Ln END;
  938. outbuf[ 0 ] := CHR( 1 );
  939. SendRecord( outbuf, ChangeCipherSpec, 0, 1 );
  940. ChangeWriteState( )
  941. END SendChangeCipherSpec;
  942. PROCEDURE ReceiveChangeCipherSpec( VAR data: ARRAY OF CHAR; ofs: LONGINT );
  943. BEGIN
  944. IF Trace THEN PrintDirection(FALSE); KernelLog.String("ChangeCipherSpec");KernelLog.Ln END;
  945. IF ORD( data[ ofs ] ) # 1 THEN (* wrong content of ChangeCipherSpec *)
  946. SendError( IllegalParameter )
  947. ELSE
  948. ChangeReadState( )
  949. END
  950. END ReceiveChangeCipherSpec;
  951. (* **********************************************************************************
  952. HANDSHAKE PROTOCOL
  953. ********************************************************************************** *)
  954. PROCEDURE SendHandshake( VAR data: ARRAY OF CHAR; hsType, ofs, len: LONGINT );
  955. VAR l: LONGINT;
  956. BEGIN
  957. ASSERT( len < 256 * 256 * 256 );
  958. l := len;
  959. data[ ofs ] := CHR( hsType );
  960. data[ ofs + 3 ] := CHR( l MOD 256 ); l := l DIV 256;
  961. data[ ofs + 2 ] := CHR( l MOD 256 ); l := l DIV 256;
  962. data[ ofs + 1 ] := CHR( l MOD 256 );
  963. IF hsType # HelloRequest THEN
  964. (* update the digests used in the finished-messages *)
  965. IF (hsType # Finished) OR (hsType # ClientHello) THEN (* Finished-msg doesn't contain digest of itself *)
  966. hsMD5send.Update( data, ofs, len + 4 );
  967. hsSHAsend.Update( data, ofs, len + 4 )
  968. END;
  969. hsMD5verify.Update( data, ofs, len + 4 );
  970. hsSHAverify.Update( data, ofs, len + 4 )
  971. END;
  972. SendRecord( data, Handshake, ofs, len + 4 );
  973. END SendHandshake;
  974. (* receives one or more handshake messages *)
  975. PROCEDURE ReceiveHandshake( VAR data: ARRAY OF CHAR; ofs, len: LONGINT );
  976. VAR msgLen, hsType, ptr, (*debug*) i: LONGINT;
  977. BEGIN
  978. ASSERT( LEN( data ) >= ofs + len );
  979. ptr := ofs;
  980. WHILE ptr < ofs + len DO (* for each handshake message *)
  981. hsType := ORD( data[ ptr ] ); (* handshake type *)
  982. msgLen := 256 * 256 * ORD( data[ ptr + 1 ] ) + 256 * ORD( data[ ptr + 2 ] ) + ORD( data[ ptr + 3 ] );
  983. (* update the digests used in the finished-messages *)
  984. hsMD5send.Update( data, ptr, msgLen + 4 );
  985. hsSHAsend.Update( data, ptr, msgLen + 4 );
  986. IF hsType # Finished THEN (* Finished-msg doesn't contain digest of itself *)
  987. hsMD5verify.Update( data, ptr, msgLen + 4 );
  988. hsSHAverify.Update( data, ptr, msgLen + 4 )
  989. END;
  990. Transition( data, Handshake, hsType, ptr + 4, msgLen );
  991. ptr := ptr + 4 + msgLen
  992. END
  993. END ReceiveHandshake;
  994. PROCEDURE ReceiveV2Handshake( VAR data: ARRAY OF CHAR; ofs, len: LONGINT );
  995. BEGIN
  996. ASSERT( data[ofs] = CHR( 1 ) ); (* v2ClientHello *)
  997. (* re-initialize hashes *)
  998. hsMD5send.Initialize( ); hsSHAsend.Initialize( );
  999. hsMD5verify.Initialize( ); hsSHAverify.Initialize( );
  1000. (* update the digests used in the finished-messages *)
  1001. hsMD5send.Update( data, ofs, len );
  1002. hsSHAsend.Update( data, ofs, len );
  1003. hsMD5verify.Update( data, ofs, len );
  1004. hsSHAverify.Update( data, ofs, len );
  1005. Transition( data, Handshake, V2ClientHello, ofs, len );
  1006. END ReceiveV2Handshake;
  1007. PROCEDURE StartHandshake;
  1008. BEGIN
  1009. Streams.OpenReader( in, SELF.conn.Receive );
  1010. Streams.OpenWriter( out, SELF.conn.Send );
  1011. SetState(ClientHandshake);
  1012. handshakeState := GenerateClientHello;
  1013. Transition(outbuf, Handshake, 0, 0, 0)
  1014. END StartHandshake;
  1015. PROCEDURE ReceiveClientHello( VAR data: ARRAY OF CHAR; ofs, len: LONGINT ): LONGINT;
  1016. VAR
  1017. nofSuites, i, idLen, idPos, pos, cipherSuite, major, minor, res: LONGINT;
  1018. BEGIN
  1019. IF Trace THEN PrintDirection(FALSE); KernelLog.String("ClientHello");KernelLog.Ln END;
  1020. pos := ofs;
  1021. (* version check *)
  1022. major := ORD( data[ pos ] ); minor := ORD( data[ pos + 1 ] );
  1023. IF Trace THEN KernelLog.String(" version: ");KernelLog.Int(major,1);KernelLog.String(".");KernelLog.Int(minor,1);KernelLog.Ln END;
  1024. IF ( major < 3 ) OR ( minor < 1 ) THEN (* fatal error: protocol version not supported *)
  1025. SendError( ProtocolVersion );
  1026. RETURN -1
  1027. END;
  1028. INC( pos, 2 );
  1029. (* 32 bytes client random *)
  1030. FOR i := 0 TO 31 DO pendingSecurityParameters.clientRandom[ i ] := data[ pos + i ] END;
  1031. INC( pos, 32 );
  1032. IF Trace THEN KernelLog.String("SERVER client random:"); KernelLog.Ln; KernelLog.Buffer(pendingSecurityParameters.clientRandom, 0, 32); KernelLog.Ln END;
  1033. (* session id *)
  1034. idLen := ORD( data[ pos ] );
  1035. idPos := pos + 1;
  1036. INC( pos, idLen + 1 );
  1037. (* cipher-suites *)
  1038. nofSuites := (256 * ORD( data[ pos ] ) + ORD( data[ pos + 1 ] )) DIV 2; (* number of cipher-suites supported by the client *)
  1039. INC( pos, 2 );
  1040. IF idLen = SessionIdLength THEN (* client attempted session resumption *)
  1041. session := context.FindSessionByID( data, idPos, idLen );
  1042. IF session # NIL THEN
  1043. (* check: is the resumed session's cipher-suite contained by the client-hello ? *)
  1044. FOR i := 0 TO nofSuites - 1 DO
  1045. cipherSuite := 256 * ORD( data[ pos + 2 * i ] ) + ORD( data[ pos + 2 * i + 1 ] );
  1046. IF cipherSuite = session.cipherSuite THEN (* session resumption *)
  1047. pendingSecurityParameters.cipherSuite := session.cipherSuite;
  1048. IF Trace THEN KernelLog.String("ciphersuite: ");KernelLog.Int(pendingSecurityParameters.cipherSuite, 8 );KernelLog.Ln END;
  1049. RETURN GenerateHelloWithResumption
  1050. END
  1051. END
  1052. END
  1053. END;
  1054. (* establish new session *)
  1055. session := context.GetNewServerSession( );
  1056. (* choose cipher-suite *)
  1057. i := 0;
  1058. LOOP
  1059. cipherSuite := 256 * ORD( data[ pos + 2 * i ] ) + ORD( data[ pos + 2 * i + 1 ] );
  1060. IF Trace THEN KernelLog.String("Server: client accepts cipher suite: "); KernelLog.Int(cipherSuite, 0); KernelLog.Ln END;
  1061. IF context.policy.IsSupported( cipherSuite ) THEN
  1062. EXIT
  1063. END;
  1064. INC( i );
  1065. IF i = nofSuites THEN EXIT END
  1066. END;
  1067. IF cipherSuite = 0 THEN (* no compatible cipher-suite found *)
  1068. IF Trace THEN KernelLog.String("Server: No common cipher suite found"); KernelLog.Ln END;
  1069. SendError( HandshakeFailure );
  1070. RETURN -1
  1071. END;
  1072. SELF.session.cipherSuite := cipherSuite;
  1073. PrepareSecurityParameters( pendingSecurityParameters, cipherSuite, res );
  1074. IF res < 0 THEN
  1075. IF Trace THEN KernelLog.String("Server: Error preparing cipher suite"); KernelLog.Ln END;
  1076. SendError( HandshakeFailure );
  1077. RETURN -1
  1078. END;
  1079. PrepareConnectionState( pendingWriteState, cipherSuite, res );
  1080. IF res < 0 THEN
  1081. IF Trace THEN KernelLog.String("Server: Error preparing pending write state"); KernelLog.Ln END;
  1082. SendError( HandshakeFailure );
  1083. RETURN -1
  1084. END;
  1085. PrepareConnectionState( pendingReadState, cipherSuite, res );
  1086. IF res < 0 THEN
  1087. IF Trace THEN KernelLog.String("Server: Error preparing pending read state"); KernelLog.Ln END;
  1088. SendError( HandshakeFailure );
  1089. RETURN -1
  1090. END;
  1091. (* ignore compression method *)
  1092. RETURN GenerateServerHello
  1093. END ReceiveClientHello;
  1094. PROCEDURE SendClientHello(VAR data: ARRAY OF CHAR; ofs: LONGINT);
  1095. VAR
  1096. pos, i: LONGINT;
  1097. BEGIN
  1098. IF Trace THEN PrintDirection(TRUE); KernelLog.String("ClientHello");KernelLog.Ln END;
  1099. ASSERT( ofs > 3 );
  1100. pos := ofs;
  1101. (* client version *)
  1102. data[ pos ] := version[ 0 ]; data[ pos + 1 ] := version[ 1 ]; (* only 3.1 is supported *)
  1103. INC( pos, 2 );
  1104. (* client random bytes generation*)
  1105. Create32RandomBytes( pendingSecurityParameters.clientRandom );
  1106. FOR i := 0 TO 31 DO data[ pos + i ] := pendingSecurityParameters.clientRandom[ i ] END; (* copy random to outbuf *)
  1107. INC( pos, 32 );
  1108. (* session-id *)
  1109. IF session # NIL THEN
  1110. (* if a previous session is available, ask server to resume it. *)
  1111. data[ pos ] := CHR( session.idLength );
  1112. INC(pos);
  1113. FOR i := 0 TO session.idLength - 1 DO data[pos + i] := session.id[i] END;
  1114. INC(pos, session.idLength)
  1115. ELSE
  1116. data[pos] := 0X;
  1117. INC(pos)
  1118. END;
  1119. (* cipher-suite: length, then suite *)
  1120. data[pos] := CHR((2 * context.policy.nofCipherSuites) DIV 256);
  1121. data[pos + 1] := CHR((2 * context.policy.nofCipherSuites) MOD 256);
  1122. INC(pos, 2);
  1123. FOR i := 0 TO context.policy.nofCipherSuites - 1 DO
  1124. data[ pos ] := CHR(context.policy.cipherSuites[i] DIV 256);
  1125. data[ pos + 1 ] := CHR(context.policy.cipherSuites[i] MOD 256);
  1126. INC( pos, 2 )
  1127. END;
  1128. (* compression-method *)
  1129. data[ pos ] := 1X;
  1130. INC( pos );
  1131. data[ pos ] := 0X;
  1132. INC( pos );
  1133. SendHandshake( data, ClientHello, ofs - 4, pos - ofs)
  1134. END SendClientHello;
  1135. PROCEDURE ReceiveV2ClientHello( VAR data: ARRAY OF CHAR; ofs, len: LONGINT ): LONGINT;
  1136. VAR nofSuites, idLen, challengeLen, i, cipherSuite, res: LONGINT;
  1137. BEGIN
  1138. IF Trace THEN PrintDirection(FALSE); KernelLog.String("SSLv2.0 ClientHello");KernelLog.Ln END;
  1139. nofSuites := ( 256 * ORD(data[ofs+3]) + ORD(data[ofs+4]) ) DIV 3;
  1140. idLen := 256 * ORD(data[ofs+5]) + ORD(data[ofs+6]);
  1141. challengeLen := 256 * ORD(data[ofs+7]) + ORD(data[ofs+8]);
  1142. (* if an SSLv2.0-ClientHello is received, a new session has to be established, because a client sends an TLSv1.0-ClientHello when resuming a session *)
  1143. session := context.GetNewServerSession( );
  1144. (* choose cipher-suite *)
  1145. INC( ofs, 9);
  1146. i := 0;
  1147. LOOP
  1148. cipherSuite := 256*256*ORD( data[ ofs + 3 * i ] ) + 256 * ORD( data[ ofs + 3 * i + 1 ] ) + ORD( data[ ofs + 3 * i + 2 ] );
  1149. IF context.policy.IsSupported( cipherSuite ) THEN
  1150. EXIT
  1151. END;
  1152. INC( i );
  1153. IF (i = nofSuites) OR (ofs + 3 * i + 2 >= LEN(data)) THEN EXIT END
  1154. END;
  1155. IF cipherSuite = 0 THEN (* no compatible cipher-suite found *)
  1156. SendError( HandshakeFailure );
  1157. RETURN -1
  1158. END;
  1159. SELF.session.cipherSuite := cipherSuite;
  1160. PrepareSecurityParameters( pendingSecurityParameters, cipherSuite, res );
  1161. IF res < 0 THEN
  1162. SendError( HandshakeFailure );
  1163. RETURN -1
  1164. END;
  1165. PrepareConnectionState( pendingWriteState, cipherSuite, res );
  1166. IF res < 0 THEN
  1167. SendError( HandshakeFailure );
  1168. RETURN -1
  1169. END;
  1170. PrepareConnectionState( pendingReadState, cipherSuite, res );
  1171. IF res < 0 THEN
  1172. SendError( HandshakeFailure );
  1173. RETURN -1
  1174. END;
  1175. INC( ofs, nofSuites * 3 );
  1176. (* session id *)
  1177. IF idLen = SessionIdLength THEN (* client attempted session resumption *)
  1178. session := context.FindSessionByID( data, ofs, idLen );
  1179. IF session # NIL THEN
  1180. RETURN GenerateHelloWithResumption
  1181. END
  1182. END;
  1183. INC( ofs, idLen );
  1184. (* 32 bytes client random *)
  1185. FOR i := 0 TO 31-challengeLen DO pendingSecurityParameters.clientRandom[ i ] := CHR(0) END;
  1186. FOR i := 0 TO challengeLen-1 DO pendingSecurityParameters.clientRandom[ 32-challengeLen + i ] := data[ ofs + i ] END;
  1187. RETURN GenerateServerHello
  1188. END ReceiveV2ClientHello;
  1189. PROCEDURE ReceiveServerHello(VAR data: ARRAY OF CHAR; ofs, len: LONGINT): LONGINT;
  1190. VAR
  1191. pos, major, minor, i, idLen, idPos, cipherSuite, res: LONGINT;
  1192. BEGIN
  1193. IF Trace THEN PrintDirection(FALSE); KernelLog.String("ServerHello");KernelLog.Ln END;
  1194. pos := ofs;
  1195. (* version check *)
  1196. major := ORD( data[ pos ] ); minor := ORD( data[ pos + 1 ] );
  1197. IF ( major < 3 ) OR ( minor < 1 ) THEN (* fatal error: protocol version not supported *)
  1198. IF Trace THEN KernelLog.String("Incompatible protocol version"); KernelLog.Ln END;
  1199. RETURN -1
  1200. END;
  1201. INC( pos, 2 );
  1202. (* 32 bytes server random *)
  1203. FOR i := 0 TO 31 DO pendingSecurityParameters.serverRandom[ i ] := data[ pos + i ] END;
  1204. INC( pos, 32 );
  1205. (* session id *)
  1206. idLen := ORD( data[ pos ] );
  1207. idPos := pos + 1;
  1208. INC( pos, idLen + 1 );
  1209. IF session # NIL THEN
  1210. (* See if session was restored *)
  1211. session := context.FindSessionByID(data, idPos, idLen);
  1212. END;
  1213. IF session = NIL THEN
  1214. (* create a new session *)
  1215. NEW(session, TRUE, data, idPos, idLen, context.policy.sessionLifetime);
  1216. END;
  1217. (* cipher-suite selected by the server*)
  1218. cipherSuite := 250 * ORD( data[ pos] ) + ORD( data[ pos + 1 ] );
  1219. SELF.session.cipherSuite := cipherSuite;
  1220. PrepareSecurityParameters( pendingSecurityParameters, cipherSuite, res );
  1221. IF res < 0 THEN
  1222. IF Trace THEN KernelLog.String("Failed to Prepare TLS security parameters"); KernelLog.Ln END;
  1223. RETURN -1
  1224. END;
  1225. PrepareConnectionState( pendingWriteState, cipherSuite, res );
  1226. IF res < 0 THEN
  1227. IF Trace THEN KernelLog.String("Failed to Prepare TLS pending write state"); KernelLog.Ln END;
  1228. RETURN -1
  1229. END;
  1230. PrepareConnectionState( pendingReadState, cipherSuite, res );
  1231. IF res < 0 THEN
  1232. IF Trace THEN KernelLog.String("Failed to Prepare TLS pending read state"); KernelLog.Ln END;
  1233. RETURN -1
  1234. END;
  1235. (* ignore compression method *)
  1236. RETURN AwaitCertificate
  1237. END ReceiveServerHello;
  1238. PROCEDURE SendServerHello( VAR data: ARRAY OF CHAR; ofs: LONGINT );
  1239. VAR i, pos: LONGINT;
  1240. BEGIN
  1241. IF Trace THEN PrintDirection(TRUE); KernelLog.String("ServerHello");KernelLog.Ln END;
  1242. ASSERT( ofs > 3 );
  1243. pos := ofs;
  1244. (* server version *)
  1245. data[ pos ] := version[ 0 ]; data[ pos + 1 ] := version[ 1 ]; (* only 3.1 is supported *)
  1246. INC( pos, 2 );
  1247. (* server random bytes generation*)
  1248. Create32RandomBytes( pendingSecurityParameters.serverRandom );
  1249. FOR i := 0 TO 31 DO data[ pos + i ] := pendingSecurityParameters.serverRandom[ i ] END; (* copy random to outbuf *)
  1250. INC( pos, 32 );
  1251. (* session-id *)
  1252. data[ pos ] := CHR( session.idLength );
  1253. INC( pos );
  1254. FOR i := 0 TO session.idLength - 1 DO data[ pos + i ] := session.id[ i ] END; (* copy session-id to data *)
  1255. INC( pos, session.idLength );
  1256. (* cipher-suite *)
  1257. data[ pos ] := CHR( pendingSecurityParameters.cipherSuite DIV 250 );
  1258. data[ pos + 1 ] := CHR( pendingSecurityParameters.cipherSuite MOD 250 );
  1259. INC( pos, 2 );
  1260. (* compression-method *)
  1261. data[ pos ] := CHR( 0 );
  1262. INC( pos );
  1263. SendHandshake( data, ServerHello, ofs-4, pos-ofs )
  1264. END SendServerHello;
  1265. PROCEDURE SendClientKeyExchange(VAR data: ARRAY OF CHAR; ofs: LONGINT): LONGINT;
  1266. VAR
  1267. length: LONGINT;
  1268. BEGIN
  1269. IF Trace THEN
  1270. PrintDirection(TRUE);
  1271. KernelLog.String("Client Key Exchange"); KernelLog.Ln
  1272. END;
  1273. context.GetRsaPublicKey;
  1274. (* Premaster secret *)
  1275. session.preMasterSecret[0] := version[0];
  1276. session.preMasterSecret[1] := version[1];
  1277. Utils.RandomBytes(session.preMasterSecret, 2, 46);
  1278. PKCS1.Encrypt(session.preMasterSecret, 0, 48, context.rsaPublicKey, 2, data, ofs + 2, length);
  1279. ASSERT(length # 0);
  1280. data[ofs] := CHR(length DIV 256);
  1281. data[ofs + 1] := CHR(length MOD 256);
  1282. SendHandshake(data, ClientKeyExchange, ofs - 4, length + 2);
  1283. (* Generate master secret. Done in the end, because premaster secret is eraased. *)
  1284. GenerateMasterSecret;
  1285. GenerateKeys;
  1286. InitializeConnectionState( SELF.pendingWriteState, SELF.pendingSecurityParameters );
  1287. InitializeConnectionState( SELF.pendingReadState, SELF.pendingSecurityParameters );
  1288. RETURN GenerateChangeCipherSpec
  1289. END SendClientKeyExchange;
  1290. PROCEDURE ReceiveClientKeyExchange(CONST data: ARRAY OF CHAR; ofs, len: LONGINT );
  1291. VAR
  1292. encryptedPremasterSecret, premasterSecret: CryptoBigNumbers.BigNumber;
  1293. tmp: ARRAY 512 OF CHAR;
  1294. i: LONGINT;
  1295. BEGIN
  1296. INC( ofs, 2 ); DEC( len, 2 ); (* the two first bytes have to be ignored *)
  1297. IF Trace THEN
  1298. PrintDirection(FALSE);
  1299. KernelLog.String("ClientKeyExchange");KernelLog.Ln;
  1300. END;
  1301. (* decryption of the PreMasterSecret *)
  1302. CryptoBigNumbers.AssignBin( encryptedPremasterSecret, data, ofs, len );
  1303. premasterSecret := SELF.context.rsaPrivateKey.Decrypt( encryptedPremasterSecret );
  1304. IF premasterSecret = NIL THEN
  1305. IF Trace THEN KernelLog.String("Decryption of PreMasterSecret was NOT successful!");KernelLog.Ln END;
  1306. SendError( IllegalParameter )
  1307. END;
  1308. CryptoBigNumbers.GetBinaryValue( premasterSecret, tmp, 0 );
  1309. (* pkcs#1 block type 2 has to be used *)
  1310. IF ( tmp[ 0 ] # CHR( 0 ) ) OR ( tmp[ 1 ] # CHR( 2 ) )THEN SendError( IllegalParameter ) END;
  1311. i := 10; (* there are at least 8 padding bytes *)
  1312. WHILE tmp[ i ] # CHR( 0 ) DO INC( i ) END; (* padding ends with a zero-byte *)
  1313. INC( i );
  1314. SELF.session.SetPreMasterSecret( tmp, i );
  1315. GenerateMasterSecret( );
  1316. GenerateKeys( );
  1317. InitializeConnectionState( SELF.pendingWriteState, SELF.pendingSecurityParameters );
  1318. InitializeConnectionState( SELF.pendingReadState, SELF.pendingSecurityParameters )
  1319. END ReceiveClientKeyExchange;
  1320. PROCEDURE ReceiveCertificate( VAR data: ARRAY OF CHAR; ofs, len: LONGINT ): LONGINT;
  1321. VAR
  1322. pos, length, lengthP3: LONGINT;
  1323. BEGIN
  1324. IF Trace THEN
  1325. PrintDirection(FALSE);
  1326. KernelLog.String("Certificate"); KernelLog.Ln;
  1327. END;
  1328. (* Get Certificate Length. First 3 bytes: length + 3, next 3 bytes: length *)
  1329. lengthP3 := ORD(data[ofs]) * 256 * 256 + ORD(data[ofs + 1]) * 256 + ORD(data[ofs + 2]);
  1330. length := ORD(data[ofs + 3]) * 256 * 256 + ORD(data[ofs + 4]) * 256 + ORD(data[ofs + 5]);
  1331. (*ASSERT(lengthP3 = length + 3);*)
  1332. context.lengthOfRsaCertificate := length;
  1333. (* Get content, including first 6 bytes *)
  1334. FOR pos := 0 TO length + 5 DO
  1335. context.rsaCertificate[pos] := data[pos + ofs]
  1336. END;
  1337. (* Check certificate *)
  1338. RETURN AwaitServerHelloDone
  1339. END ReceiveCertificate;
  1340. PROCEDURE SendCertificate( VAR data: ARRAY OF CHAR; ofs: LONGINT );
  1341. VAR i: LONGINT;
  1342. BEGIN
  1343. ASSERT( ofs > 3 );
  1344. IF Trace THEN PrintDirection(TRUE); KernelLog.String("Certificate");KernelLog.Ln END;
  1345. FOR i := 0 TO context.lengthOfRsaCertificate-1 DO
  1346. data[ ofs + i ] := context.rsaCertificate[ i ];
  1347. END;
  1348. SendHandshake( data, Certificate, ofs-4, context.lengthOfRsaCertificate );
  1349. END SendCertificate;
  1350. PROCEDURE SendServerHelloDone( VAR data: ARRAY OF CHAR; ofs: LONGINT );
  1351. BEGIN
  1352. ASSERT( ofs > 3 );
  1353. IF Trace THEN PrintDirection(TRUE); KernelLog.String("ServerHelloDone");KernelLog.Ln END;
  1354. SendHandshake( data, ServerHelloDone, ofs-4, 0 )
  1355. END SendServerHelloDone;
  1356. PROCEDURE ReceiveServerHelloDone(CONST data: ARRAY OF CHAR; ofs, len: LONGINT): LONGINT;
  1357. BEGIN
  1358. IF Trace THEN PrintDirection(FALSE); KernelLog.String("ServerHelloDone"); KernelLog.Ln END;
  1359. RETURN GenerateClientKeyExchange
  1360. END ReceiveServerHelloDone;
  1361. PROCEDURE SendFinished( VAR data: ARRAY OF CHAR; ofs: LONGINT );
  1362. VAR
  1363. seed: ARRAY 36 OF CHAR;
  1364. verifyData: ARRAY 12 OF CHAR;
  1365. i: LONGINT;
  1366. prf: PRF;
  1367. BEGIN
  1368. IF Trace THEN PrintDirection(TRUE); KernelLog.String("Finished");KernelLog.Ln END;
  1369. ASSERT( ofs > 3 );
  1370. hsMD5send.GetHash( seed, 0 ); hsSHAsend.GetHash( seed, 16 ); (* concatenate md5 and sha output *)
  1371. NEW( prf );
  1372. IF client THEN
  1373. prf.GetBytes( SELF.session.masterSecret, seed, verifyData, "client finished", 48, 36, 12 )
  1374. ELSE
  1375. prf.GetBytes( SELF.session.masterSecret, seed, verifyData, "server finished", 48, 36, 12 )
  1376. END;
  1377. FOR i := 0 TO 11 DO
  1378. data[ ofs + i ] := verifyData[ i ]
  1379. END;
  1380. SendHandshake( data, Finished, ofs-4, 12 )
  1381. END SendFinished;
  1382. PROCEDURE ReceiveFinished(CONST data: ARRAY OF CHAR; ofs, len: LONGINT );
  1383. VAR
  1384. seed: ARRAY 36 OF CHAR;
  1385. verifyData: ARRAY 12 OF CHAR;
  1386. prf: PRF;
  1387. i: LONGINT;
  1388. BEGIN
  1389. IF Trace THEN PrintDirection(FALSE); KernelLog.String("Finished"); KernelLog.Ln END;
  1390. ASSERT( len = 12 );
  1391. hsMD5verify.GetHash( seed, 0 ); hsSHAverify.GetHash( seed, 16 ); (* concatenate md5 and sha output *)
  1392. NEW( prf );
  1393. IF client THEN
  1394. prf.GetBytes( SELF.session.masterSecret, seed, verifyData, "server finished", 48, 36, 12 )
  1395. ELSE
  1396. prf.GetBytes( SELF.session.masterSecret, seed, verifyData, "client finished", 48, 36, 12 )
  1397. END;
  1398. FOR i := 0 TO 11 DO
  1399. IF verifyData[ i ] # data[ ofs + i ] THEN
  1400. SendError( DecryptError );
  1401. RETURN
  1402. END
  1403. END
  1404. END ReceiveFinished;
  1405. (* **********************************************************************************
  1406. ALERT PROTOCOL
  1407. ********************************************************************************** *)
  1408. PROCEDURE ReceiveAlert( VAR data: ARRAY OF CHAR; ofs, len: LONGINT );
  1409. VAR level, description, ptr: LONGINT;
  1410. BEGIN
  1411. ptr := ofs;
  1412. WHILE ptr < ofs + len DO (* for each Alert-message *)
  1413. level := ORD( data[ ptr ] );
  1414. description := ORD( data[ ptr + 1 ] );
  1415. IF level = Warning THEN
  1416. ReceiveWarning( description )
  1417. ELSIF level = Fatal THEN
  1418. ReceiveError( description )
  1419. ELSE (* illegal level *)
  1420. SendError( IllegalParameter )
  1421. END;
  1422. INC( ptr, 2 )
  1423. END
  1424. END ReceiveAlert;
  1425. PROCEDURE ReceiveWarning( desc: LONGINT);
  1426. BEGIN
  1427. (* always send an error; this could be more sophisticated *)
  1428. tlsErrorCause := desc;
  1429. SendError( CloseNotify )
  1430. END ReceiveWarning;
  1431. PROCEDURE ReceiveError( alertType: LONGINT);
  1432. BEGIN
  1433. IF Trace THEN
  1434. PrintDirection(FALSE);
  1435. KernelLog.String("Error");KernelLog.Ln;
  1436. KernelLog.String(" alertType: ");KernelLog.Int(alertType, 3);KernelLog.Ln;
  1437. END;
  1438. IF session # NIL THEN SELF.session.Invalidate( ) END;
  1439. SELF.conn.Close( );
  1440. applicationDataPipe.Close();
  1441. SetState(TCP.Closed);
  1442. END ReceiveError;
  1443. PROCEDURE SendWarning( alertType: LONGINT );
  1444. BEGIN
  1445. IF Trace THEN
  1446. PrintDirection(TRUE);
  1447. KernelLog.String("Warning");KernelLog.Ln;
  1448. KernelLog.String(" alertType: ");KernelLog.Int(alertType, 3);KernelLog.Ln;
  1449. END;
  1450. outbuf[ 0 ] := CHR( 1 ); (* level: warning *)
  1451. outbuf[ 1 ] := CHR( alertType );
  1452. SendRecord( outbuf, Alert, 0, 2 );
  1453. END SendWarning;
  1454. PROCEDURE SendError( alertType: LONGINT );
  1455. BEGIN
  1456. IF Trace THEN
  1457. PrintDirection(TRUE);
  1458. KernelLog.String("Error");KernelLog.Ln;
  1459. KernelLog.String(" alertType: ");KernelLog.Int(alertType, 3);KernelLog.Ln;
  1460. END;
  1461. outbuf[ 0 ] := CHR( 2 ); (* level: fatal *)
  1462. outbuf[ 1 ] := CHR( alertType );
  1463. SendRecord( outbuf, Alert, 0, 2 );
  1464. IF session # NIL THEN SELF.session.Invalidate( ) END;
  1465. SELF.conn.Close( );
  1466. applicationDataPipe.Close();
  1467. SetState(TCP.Closed);
  1468. END SendError;
  1469. (* **********************************************************************************
  1470. FINITE STATE MACHINE
  1471. ********************************************************************************** *)
  1472. PROCEDURE Transition( VAR data: ARRAY OF CHAR; action, subAction, ofs, len: LONGINT );
  1473. VAR dummy: ARRAY 1 OF CHAR;
  1474. res : LONGINT;
  1475. BEGIN
  1476. IF action = ChangeCipherSpec THEN
  1477. CASE handshakeState OF
  1478. | AwaitChangeSpec:
  1479. ReceiveChangeCipherSpec( data, ofs );
  1480. handshakeState := AwaitFinished
  1481. | AwaitChangeSpecWithResumption:
  1482. ReceiveChangeCipherSpec( data, ofs );
  1483. handshakeState := AwaitFinishedWithResumption
  1484. ELSE
  1485. SendError( UnexpectedMessage )
  1486. END
  1487. ELSIF action = Handshake THEN
  1488. IF State()= ServerHandshake THEN
  1489. CASE handshakeState OF
  1490. | AwaitClientHello:
  1491. IF subAction = ClientHello THEN
  1492. handshakeState := ReceiveClientHello( data, ofs, len );
  1493. Transition( dummy, Handshake, 0, 0, 0 )
  1494. ELSIF subAction = V2ClientHello THEN
  1495. handshakeState := ReceiveV2ClientHello( data, ofs, len );
  1496. Transition( dummy, Handshake, 0, 0, 0 )
  1497. ELSE (* fatal error *)
  1498. SendError( UnexpectedMessage )
  1499. END
  1500. | GenerateServerHello: (* establish new session *)
  1501. SendServerHello( outbuf, 4 );
  1502. SendCertificate( outbuf, 4 );
  1503. handshakeState := GenerateServerHelloDone;
  1504. Transition( dummy, Handshake, 0, 0, 0 )
  1505. | GenerateServerHelloDone:
  1506. SendServerHelloDone( outbuf, 4 );
  1507. handshakeState := AwaitClientKeyExchange;
  1508. | AwaitClientKeyExchange:
  1509. IF subAction = ClientKeyExchange THEN
  1510. ReceiveClientKeyExchange( data, ofs, len );
  1511. handshakeState := AwaitChangeSpec;
  1512. ELSE (* fatal error *)
  1513. SendError( UnexpectedMessage )
  1514. END
  1515. | AwaitFinished:
  1516. IF subAction = Finished THEN
  1517. ReceiveFinished( data, ofs, len );
  1518. handshakeState := GenerateChangeCipherSpec;
  1519. Transition( dummy, Handshake, 0, 0, 0 )
  1520. ELSE (* fatal error *)
  1521. SendError( UnexpectedMessage )
  1522. END
  1523. | GenerateChangeCipherSpec:
  1524. SendChangeCipherSpec;
  1525. SendFinished( outbuf, 4 );
  1526. handshakeState := HandshakeFinished;
  1527. SetState(TCP.Established);
  1528. IF SELF.context.policy.sessionResumptionEnabled THEN
  1529. SELF.context.StoreSession( SELF.session )
  1530. END
  1531. | GenerateHelloWithResumption: (* session resumption *)
  1532. SendServerHello( outbuf, 4 );
  1533. PrepareSecurityParameters( pendingSecurityParameters, pendingSecurityParameters.cipherSuite, res );
  1534. IF res < 0 THEN
  1535. SendError( UnexpectedMessage )
  1536. END;
  1537. PrepareConnectionState( pendingWriteState, pendingSecurityParameters.cipherSuite,res );
  1538. IF res < 0 THEN
  1539. SendError( HandshakeFailure );
  1540. END;
  1541. PrepareConnectionState( pendingReadState, pendingSecurityParameters.cipherSuite, res );
  1542. IF res < 0 THEN
  1543. SendError( HandshakeFailure );
  1544. END;
  1545. GenerateKeys( );
  1546. InitializeConnectionState( SELF.pendingWriteState, SELF.pendingSecurityParameters );
  1547. InitializeConnectionState( SELF.pendingReadState, SELF.pendingSecurityParameters );
  1548. SendChangeCipherSpec;
  1549. SendFinished( outbuf, 4 );
  1550. handshakeState := AwaitChangeSpecWithResumption
  1551. | AwaitFinishedWithResumption:
  1552. IF subAction = Finished THEN
  1553. ReceiveFinished( data, ofs, len );
  1554. handshakeState := HandshakeFinished;
  1555. SetState(TCP.Established);
  1556. ELSE (* fatal error *)
  1557. SendError( UnexpectedMessage )
  1558. END
  1559. END (* CASE *)
  1560. ELSIF State() = ClientHandshake THEN
  1561. CASE handshakeState OF
  1562. GenerateClientHello:
  1563. SendClientHello(outbuf, 4);
  1564. handshakeState := AwaitServerHello
  1565. |AwaitServerHello:
  1566. handshakeState := ReceiveServerHello(data, ofs, len);
  1567. |AwaitCertificate:
  1568. handshakeState := ReceiveCertificate(data, ofs, len);
  1569. |AwaitServerHelloDone:
  1570. handshakeState := ReceiveServerHelloDone(data, ofs, len);
  1571. Transition(dummy, Handshake, 0, 0, 0)
  1572. |GenerateClientKeyExchange:
  1573. handshakeState := SendClientKeyExchange(outbuf, 4);
  1574. Transition(dummy, Handshake, 0, 0, 0)
  1575. |GenerateChangeCipherSpec:
  1576. SendChangeCipherSpec;
  1577. SendFinished(outbuf, 4);
  1578. handshakeState := AwaitChangeSpec
  1579. |AwaitChangeSpec:
  1580. ReceiveChangeCipherSpec(data, ofs);
  1581. handshakeState := AwaitFinished
  1582. |AwaitFinished:
  1583. ReceiveFinished(data, ofs, len);
  1584. SetState(TCP.Established);
  1585. END
  1586. ELSIF State() = TCP.Established THEN
  1587. IF subAction = ClientHello THEN (* the only handshake msg a server should receive after a finished handshake *)
  1588. SetState(ServerHandshake);
  1589. handshakeState := ReceiveClientHello( data, ofs, len );
  1590. Transition( dummy, Handshake, 0, 0, 0 )
  1591. ELSE (* fatal error *)
  1592. SendError( UnexpectedMessage )
  1593. END
  1594. END
  1595. END;
  1596. END Transition;
  1597. (* **********************************************************************************
  1598. UTILITIES
  1599. ********************************************************************************** *)
  1600. PROCEDURE Create32RandomBytes( VAR data: ARRAY OF CHAR );
  1601. VAR i, time, date, timestamp: LONGINT;
  1602. BEGIN
  1603. ASSERT( LEN( data ) > 31 );
  1604. (* 4 bytes timestamp *)
  1605. Clock.Get( date, time );
  1606. timestamp := BIT.LXOR( date, time );
  1607. FOR i := 3 TO 0 BY -1 DO
  1608. data[ i ] := CHR( timestamp );
  1609. timestamp := timestamp DIV 256
  1610. END;
  1611. (* 28 random bytes *)
  1612. Utils.RandomBytes( data, 4, 28 )
  1613. END Create32RandomBytes;
  1614. (** Prints the correct S > C or C > S depending on current action and state *)
  1615. PROCEDURE PrintDirection(send: BOOLEAN);
  1616. BEGIN
  1617. IF client & send THEN
  1618. KernelLog.String("CLIENT: C > S ")
  1619. ELSIF client & ~send THEN
  1620. KernelLog.String("CLIENT: S > C ")
  1621. ELSIF ~client & send THEN
  1622. KernelLog.String("SERVER: S > C ")
  1623. ELSE
  1624. KernelLog.String("SERVER: C > S ")
  1625. END
  1626. END PrintDirection;
  1627. BEGIN { ACTIVE }
  1628. AwaitStateNotEqual(TCP.Unused);
  1629. IF client THEN
  1630. StartHandshake;
  1631. REPEAT
  1632. ReceiveRecord
  1633. UNTIL (State() = TCP.Established) OR (State() = TCP.Closed);
  1634. IF State() = TCP.Established THEN
  1635. REPEAT
  1636. ReceiveRecord
  1637. UNTIL (State() = TCP.Closed) OR (in.res # Streams.Ok);
  1638. Close
  1639. END
  1640. ELSE
  1641. IF State() # TCP.Listen THEN
  1642. (* listen for incoming messages *)
  1643. REPEAT
  1644. ReceiveRecord( )
  1645. UNTIL (State() = TCP.Closed) OR (in.res # Streams.Ok);
  1646. Close();
  1647. END;
  1648. END
  1649. END Connection;
  1650. VAR
  1651. version: ARRAY 2 OF CHAR;
  1652. defaultCipherPolicy: Policy;
  1653. (** Returns a new connection with a reasonnable default policy *)
  1654. PROCEDURE GetConnection * (): Connection;
  1655. VAR
  1656. con: Connection;
  1657. BEGIN
  1658. NEW(con);
  1659. RETURN con
  1660. END GetConnection;
  1661. (** Prepares default ciphers for TLS v1.1 *)
  1662. PROCEDURE InitDefaults;
  1663. VAR
  1664. defaultSuites:ARRAY DefaultSuitesNbr OF LONGINT;
  1665. BEGIN
  1666. (*! THESE CIPHERS ARE NOT SECURE, IMPLEMENT AND USE TLS v1.2 *)
  1667. defaultSuites[0] := TlsRsaWithIdeaCbcSha;
  1668. defaultSuites[1] := TlsRsaWith3DesEdeCbcSha;
  1669. defaultSuites[2] := TlsRsaWithRc4128Sha;
  1670. defaultSuites[3] := TlsRsaWithDesCbcSha;
  1671. NEW(defaultCipherPolicy);
  1672. defaultCipherPolicy.SetCipherSuites(defaultSuites, DefaultSuitesNbr)
  1673. END InitDefaults;
  1674. BEGIN
  1675. version[ 0 ] := CHR( 3 ); (* this implementation supports only TLS 1.0 = SSL 3.1 *)
  1676. version[ 1 ] := CHR( 1 );
  1677. InitDefaults
  1678. END TLS.
  1679. System.Free WebHTTPServerTools WebHTTPServer TLSServices TLS ~
  1680. Aos.Call WebHTTPServerTools.Start~