SSHKeys.Mod 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. MODULE SSHKeys; (* g.f. 2002.08.29 *)
  2. (* 2002.10.15 g.f. RSA hostkeys added*)
  3. IMPORT
  4. RSA := CryptoRSA, DSA := CryptoDSA, B:= CryptoBigNumbers, U := CryptoUtils, SHA1 := CryptoSHA1,
  5. MD5 := CryptoMD5, P := CryptoPrimes, G := SSHGlobals,
  6. Files, Streams, Out := KernelLog, WMDialogs, Strings;
  7. CONST
  8. Ok = WMDialogs.ResOk;
  9. Abort = WMDialogs.ResAbort;
  10. TYPE
  11. BigNumber = B.BigNumber;
  12. PROCEDURE SSHDSSVerify( dsa: DSA.Key; sig: DSA.Signature; CONST hash: ARRAY OF CHAR ): BOOLEAN;
  13. VAR h: SHA1.Hash; digest: ARRAY 20 OF CHAR;
  14. BEGIN
  15. NEW( h );
  16. h.Initialize; h.Update( hash, 0, 20 ); h.GetHash( digest, 0 );
  17. RETURN dsa.Verify( digest, 20, sig )
  18. END SSHDSSVerify;
  19. PROCEDURE SSHRSAVerify( rsa: RSA.Key; sig: BigNumber; CONST hash: ARRAY OF CHAR ): BOOLEAN;
  20. VAR h1: SHA1.Hash; h2: MD5.Hash; digest: ARRAY 20 OF CHAR;
  21. BEGIN
  22. NEW( h1 );
  23. h1.Initialize; h1.Update( hash, 0, 20 ); h1.GetHash( digest, 0 );
  24. IF rsa.Verify( digest, 20, sig ) THEN RETURN TRUE
  25. ELSE
  26. (* SSH_BUG_RSASIGMD5 in server implementation ? *)
  27. NEW( h2 );
  28. h2.Initialize; h2.Update( hash, 0, 20 ); h2.GetHash( digest, 0 );
  29. RETURN rsa.Verify( digest, 16, sig )
  30. END
  31. END SSHRSAVerify;
  32. PROCEDURE GetKeyStart( CONST keykind, host: ARRAY OF CHAR ): Files.Reader;
  33. VAR
  34. f: Files.File; r: Files.Reader;
  35. buf1, buf2: ARRAY 512 OF CHAR;
  36. i: LONGINT;
  37. names: Strings.StringArray;
  38. BEGIN
  39. f := Files.Old( G.HostkeysFile );
  40. IF f = NIL THEN RETURN NIL
  41. ELSE
  42. Files.OpenReader( r, f, 0 );
  43. REPEAT
  44. r.SkipWhitespace; r.String( buf1 );
  45. r.SkipWhitespace; r.String( buf2 );
  46. IF buf2 = keykind THEN
  47. names := Strings.Split( buf1, ',' );
  48. i := 0;
  49. REPEAT
  50. IF names[i]^ = host THEN RETURN r END;
  51. INC( i )
  52. UNTIL i >= LEN( names^ )
  53. END;
  54. r.SkipLn;
  55. UNTIL r.Available() = 0;
  56. RETURN NIL
  57. END;
  58. END GetKeyStart;
  59. PROCEDURE WriterAtEnd(): Streams.Writer;
  60. VAR
  61. f: Files.File; w: Files.Writer; r: Files.Reader; c: CHAR;
  62. BEGIN
  63. f := Files.Old( G.HostkeysFile );
  64. IF f = NIL THEN
  65. f := Files.New( G.HostkeysFile ); Files.Register( f );
  66. Files.OpenWriter( w, f, 0 );
  67. RETURN w
  68. ELSE
  69. Files.OpenReader( r, f, f.Length() -1 );
  70. r.Char( c );
  71. Files.OpenWriter( w, f, f.Length() );
  72. IF c >= ' ' THEN w.Ln END;
  73. RETURN w
  74. END;
  75. END WriterAtEnd;
  76. PROCEDURE CompareDSAKeys( CONST host: ARRAY OF CHAR; key: DSA.Key ): BOOLEAN;
  77. VAR
  78. r: Streams.Reader; w: Streams.Writer;
  79. msg: ARRAY 512 OF CHAR;
  80. res: WORD;
  81. knownKey: DSA.Key;
  82. BEGIN
  83. r := GetKeyStart( "ssh-dss", host );
  84. IF r = NIL THEN
  85. msg := "no suitable dsa hostkey found in ";
  86. Strings.Append( msg, G.HostkeysFile );
  87. Strings.AppendChar( msg, 0DX );
  88. Strings.Append( msg, "will you trust the connection anyway?" );
  89. res := WMDialogs.Message( 1, "Load Public Server Hostkey", msg, {Ok, Abort} );
  90. IF res # Ok THEN RETURN FALSE
  91. ELSE
  92. w := WriterAtEnd();
  93. w.String( host ); w.Char( ' ' );
  94. DSA.StorePublicKey( w, key );
  95. w.Update;
  96. RETURN TRUE
  97. END
  98. END;
  99. knownKey := DSA.LoadPublicKey( r );
  100. IF B.Cmp( key.y, knownKey.y ) # 0 THEN
  101. Out.String( "### error: hostkey of remote host has changed" ); Out.Ln;
  102. RETURN FALSE
  103. END;
  104. RETURN TRUE
  105. END CompareDSAKeys;
  106. PROCEDURE CompareRSAKeys( CONST host: ARRAY OF CHAR; key: RSA.Key ): BOOLEAN;
  107. VAR
  108. r: Streams.Reader; w: Streams.Writer;
  109. msg: ARRAY 512 OF CHAR;
  110. res: WORD;
  111. knownKey: RSA.Key;
  112. BEGIN
  113. r := GetKeyStart( "ssh-rsa", host );
  114. IF r = NIL THEN
  115. msg := "no suitable rsa hostkey found in ";
  116. Strings.Append( msg, G.HostkeysFile );
  117. Strings.AppendChar( msg, 0DX );
  118. Strings.Append( msg, "will you trust the connection anyway?" );
  119. res := WMDialogs.Message( 1, "Load Public Server Hostkey", msg, {Ok, Abort} );
  120. IF res # Ok THEN RETURN FALSE
  121. ELSE
  122. w := WriterAtEnd();
  123. w.String( host ); w.Char( ' ' );
  124. RSA.StorePublicKey( w, key );
  125. w.Update;
  126. RETURN TRUE
  127. END
  128. END;
  129. knownKey := RSA.ExtractPublicKey( r );
  130. IF B.Cmp( key.modulus, knownKey.modulus ) # 0 THEN
  131. Out.String( "### error: hostkey of remote host has changed" ); Out.Ln;
  132. RETURN FALSE
  133. END;
  134. RETURN TRUE
  135. END CompareRSAKeys;
  136. PROCEDURE VerifyIdentity*( CONST keyblob, signature, host, hash: ARRAY OF CHAR ): BOOLEAN;
  137. VAR
  138. name1, name2: ARRAY 128 OF CHAR; i, j, len: LONGINT;
  139. dsa: DSA.Key; dsasig: DSA.Signature;
  140. rsa: RSA.Key; e, n, rsasig: BigNumber;
  141. p, q, g, pub, r, s: BigNumber;
  142. BEGIN
  143. i := 0; U.GetString( keyblob, i, name1 );
  144. j := 0; U.GetString( signature, j, name2 );
  145. IF name1 # name2 THEN RETURN FALSE END;
  146. IF name1 = "ssh-dss" THEN
  147. U.GetBigNumber( keyblob, i, p );
  148. U.GetBigNumber( keyblob, i, q );
  149. U.GetBigNumber( keyblob, i, g );
  150. U.GetBigNumber( keyblob, i, pub );
  151. dsa := DSA.PubKey( p, q, g, pub );
  152. U.GetLength( signature, j, len );
  153. IF len # 40 THEN RETURN FALSE END;
  154. B.AssignBin( r, signature, j, 20 ); INC( j, 20 );
  155. B.AssignBin( s, signature, j, 20 );
  156. NEW( dsasig, r, s );
  157. IF SSHDSSVerify( dsa, dsasig, hash ) THEN RETURN CompareDSAKeys( host, dsa )
  158. ELSE RETURN FALSE
  159. END
  160. ELSIF name1 = "ssh-rsa" THEN
  161. U.GetBigNumber( keyblob, i, e );
  162. U.GetBigNumber( keyblob, i, n );
  163. rsa := RSA.PubKey( e, n );
  164. U.GetBigNumber( signature, j, rsasig );
  165. IF (rsa.name = "unkown") (* from openssh! *) OR SSHRSAVerify( rsa, rsasig, hash ) THEN
  166. RETURN CompareRSAKeys( host, rsa )
  167. ELSE RETURN FALSE
  168. END
  169. ELSE
  170. Out.String( "### error: unsupported public hostkey type: " ); Out.String( name1 ); Out.Ln;
  171. RETURN FALSE
  172. END;
  173. END VerifyIdentity;
  174. PROCEDURE RSAKeyGen*;
  175. CONST
  176. headline1 = "enter passphrase for new rsa key";
  177. headline2 = "repeat passphrase for new rsa key";
  178. Size = 2048;
  179. VAR
  180. pw1, pw2: ARRAY 32 OF CHAR; ignore, res: LONGINT; ok: BOOLEAN;
  181. p, q, e: BigNumber;
  182. priv, pub: RSA.Key;
  183. f: Files.File; w: Files.Writer;
  184. BEGIN
  185. REPEAT
  186. ignore := WMDialogs.QueryPassword( headline1, pw1 );
  187. ok := Strings.Length( pw1 ) > 5;
  188. IF ~ok THEN
  189. res := WMDialogs.Message( 1, "RSA Keygen", "pease insert a longer key", {Ok, Abort} );
  190. IF res = Abort THEN RETURN END
  191. END
  192. UNTIL ok;
  193. ignore := WMDialogs.QueryPassword( headline2, pw2 );
  194. IF pw1 # pw2 THEN
  195. res := WMDialogs.Message( 1, "RSA Keygen", "passphrases don't match", {Ok} );
  196. RETURN
  197. END;
  198. p := P.NewPrime( Size DIV 2, FALSE );
  199. q := P.NewPrime( Size DIV 2, FALSE );
  200. B.AssignInt( e, 3 );
  201. RSA.MakeKeys( p, q, e, "Aos rsa-key", pub, priv );
  202. f := Files.New( G.PrivateKeyFile ); Files.OpenWriter( w, f, 0 );
  203. RSA.StorePrivateKey( w, priv, pw1 );
  204. w.Update;
  205. Files.Register( f );
  206. f := Files.New( G.PublicKeyFile ); Files.OpenWriter( w, f, 0 );
  207. RSA.StorePublicKey( w, pub );
  208. w.Update;
  209. Files.Register( f );
  210. END RSAKeyGen;
  211. BEGIN
  212. END SSHKeys.
  213. .
  214. SSHKeys.RSAKeyGen ~
  215. System.Free SSHKeys ~