123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311 |
- MODULE SSHAuthorize; (* g.f. 2001.12.12 *)
- IMPORT T := SSHTransport, U := CryptoUtils, B := CryptoBigNumbers, RSA := CryptoRSA, G := SSHGlobals,
- SHA1 := CryptoSHA1, Strings, Out := KernelLog, Files, WMDialogs, Beep;
- TYPE
- Connection* = T.Connection;
- CONST
- Closed* = T.Closed; Connected* = T.Connected;
- ServiceRequest = 5X; ServiceAccept = 6X;
- UserauthRequest = 32X; UserauthFailure = 33X;
- UserauthSuccess = 34X; UserauthBanner = 35X;
- UserauthPkOk = 3CX;
- TYPE
- Password = POINTER TO RECORD
- next: Password;
- host, user, pw: ARRAY 64 OF CHAR;
- END;
- VAR
- passwords: Password;
- privKey, pubKey: RSA.Key;
- PROCEDURE GetPW( CONST host, user: ARRAY OF CHAR; VAR pw: ARRAY OF CHAR );
- VAR n: Password;
- BEGIN
- n := passwords; pw := "";
- WHILE n # NIL DO
- IF (n.host = host) & (n.user = user) THEN COPY( n.pw, pw ); RETURN END;
- n := n.next
- END
- END GetPW;
- PROCEDURE AddPW( CONST host, user, pw: ARRAY OF CHAR );
- VAR n, p: Password;
- BEGIN
- n := passwords;
- WHILE n # NIL DO
- IF (n.host = host) & (n.user = user) THEN
- (* replace pw *)
- COPY( pw, n.pw ); RETURN
- END;
- p := n; n := n.next
- END;
- IF p = NIL THEN NEW( passwords ); p := passwords
- ELSE NEW( p.next ); p := p.next
- END;
- p.next := NIL;
- COPY( host, p.host );
- COPY( user, p.user );
- COPY( pw, p.pw )
- END AddPW;
- PROCEDURE RequestService( VAR ssh: Connection; CONST service: ARRAY OF CHAR ): BOOLEAN;
- VAR p: T.Packet; d: LONGINT; buf: ARRAY 256 OF CHAR;
- BEGIN
- NEW( p, ServiceRequest, 256 );
- p.AppString( service );
- ssh.SendPacket( p );
- IF ssh.ReceivePacket( buf, d ) = ServiceAccept THEN RETURN TRUE
- ELSE ssh.Disconnect( 11, "" ); RETURN FALSE
- END
- END RequestService;
- PROCEDURE RequestAuthorizeNone( ssh: Connection; CONST user: ARRAY OF CHAR ): BOOLEAN;
- VAR p: T.Packet; msg: ARRAY 512 OF CHAR; len: LONGINT;
- BEGIN
- NEW( p, UserauthRequest, 256 );
- p.AppString( user );
- p.AppString( "ssh-connection" );
- p.AppString( "none" );
- ssh.SendPacket( p );
- RETURN ssh.ReceivePacket( msg, len ) = UserauthSuccess
- END RequestAuthorizeNone;
- PROCEDURE RequestConnPW( ssh: Connection; CONST user, host: ARRAY OF CHAR; try: LONGINT );
- VAR p: T.Packet; headline, pw: ARRAY 64 OF CHAR;
- BEGIN
- headline := "SSH: Enter Password for ";
- Strings.Append( headline, user );
- Strings.Append( headline, "@" );
- Strings.Append( headline, host );
- NEW( p, UserauthRequest, 1024 );
- p.AppString( user );
- p.AppString( "ssh-connection" );
- p.AppString( "password" );
- p.AppChar( 0X );
- IF try = 1 THEN GetPW( host, user, pw ) ELSE pw := "" END;
- IF pw = "" THEN
- Beep.Beep( 1000 );
- IGNORE WMDialogs.QueryPassword( headline, pw);
- AddPW( host, user, pw );
- END;
- p.AppString( pw );
- ssh.SendPacket( p )
- END RequestConnPW;
- PROCEDURE AuthorizePasswd( ssh: Connection; CONST host, user: ARRAY OF CHAR ): BOOLEAN;
- VAR
- msg: ARRAY 2048 OF CHAR;
- len: LONGINT; try: INTEGER;
- BEGIN
- try := 1;
- RequestConnPW( ssh, user, host, try );
- LOOP
- CASE ssh.ReceivePacket( msg, len ) OF
- | UserauthBanner:
- U.PrintBufferString( msg, 1 ); Out.Ln;
- | UserauthSuccess:
- Out.String( "password authentication succeeded" ); Out.Ln;
- RETURN TRUE
- | UserauthFailure:
- IF try > 1 THEN
- Out.String( "password authentication failed" ); Out.Ln;
- RETURN FALSE
- ELSE
- INC( try );
- RequestConnPW( ssh, user, host, try )
- END
- ELSE
- Out.String( "SSHAuthorization.AuthorizePasswd: protocol error: got " ); Out.Int( ORD( msg[0] ), 3 ); Out.Ln;
- RETURN FALSE
- END
- END
- END AuthorizePasswd;
- PROCEDURE MakePubKeyBlob( VAR buf: ARRAY OF CHAR; VAR len: LONGINT );
- BEGIN
- len := 0;
- U.PutString( buf, len, "ssh-rsa" );
- U.PutBigNumber( buf, len, pubKey.exponent );
- U.PutBigNumber( buf, len, pubKey.modulus );
- END MakePubKeyBlob;
- PROCEDURE CheckAuthorizeKey( ssh: Connection; CONST user: ARRAY OF CHAR ): BOOLEAN;
- VAR p: T.Packet; buf: ARRAY 512 OF CHAR; len :LONGINT;
- BEGIN
- MakePubKeyBlob( buf, len );
- NEW( p, UserauthRequest, 1024 );
- p.AppString( user );
- p.AppString( "ssh-connection" );
- p.AppString( "publickey" );
- p.AppChar( 0X ); (* false *)
- p.AppString( "ssh-rsa" );
- p.AppArray( buf, 0, len );
- ssh.SendPacket( p );
- IF ssh.ReceivePacket( buf, len ) # UserauthPkOk THEN
- U.PrintBufferString( buf, 1 ); Out.Ln;
- RETURN FALSE
- END;
- RETURN TRUE
- END CheckAuthorizeKey;
- PROCEDURE RequestAuthorizeKey( ssh: Connection; CONST user: ARRAY OF CHAR ): BOOLEAN;
- CONST
- Asn1DerSha1 = "3021300906052B0E03021A05000414";
- HashLen = 20;
- MsgLen = 15 + HashLen;
- EmSize = 256;
- PadLen = EmSize - MsgLen;
- VAR
- p: T.Packet;
- blob, sig, buf: ARRAY 512 OF CHAR; pos, blen, len :LONGINT;
- signature: B.BigNumber;
- sha1: SHA1.Hash;
- em: ARRAY EmSize OF CHAR;
- i: LONGINT;
- BEGIN
- ASSERT( privKey.size = 2048 );
- MakePubKeyBlob( blob, blen );
- NEW( sha1 ); sha1.Initialize;
- pos := 0;
- U.PutArray( buf, pos, ssh.sessionId, 0, 20 );
- U.PutChar( buf, pos, UserauthRequest );
- U.PutString( buf, pos, user );
- U.PutString( buf, pos, "ssh-connection" );
- U.PutString( buf, pos, "publickey" );
- U.PutChar( buf, pos, 1X );
- U.PutString( buf, pos, "ssh-rsa" );
- U.PutArray( buf, pos, blob, 0, blen );
- sha1.Update( buf, 0, pos );
- (* padding PKCS1 type 1 *)
- em[0] := 0X; em[1] := 1X;
- FOR i := 2 TO PadLen - 2 DO em[i] := 0FFX END;
- em[PadLen - 1] := 0X;
- U.Hex2Bin( Asn1DerSha1, 0, em, EmSize - MsgLen, 15 );
- sha1.GetHash( em, EmSize - HashLen );
- signature := privKey.Sign( em, EmSize );
- pos := 0;
- U.PutString( sig, pos, "ssh-rsa" );
- U.PutBigNumber( sig, pos, signature );
- NEW( p, UserauthRequest, 1024 );
- p.AppString( user );
- p.AppString( "ssh-connection" );
- p.AppString( "publickey" );
- p.AppChar( 1X ); (* true *)
- p.AppString( "ssh-rsa" );
- p.AppArray( blob, 0, blen );
- p.AppArray( sig, 0, pos );
- ssh.SendPacket( p );
- IF ssh.ReceivePacket( buf, len ) # UserauthSuccess THEN
- U.PrintBufferString( buf, 1 ); Out.Ln;
- Out.String( "public key authentication failed" ); Out.Ln;
- RETURN FALSE
- END;
- Out.String( "public key authentication succeeded" ); Out.Ln;
- RETURN TRUE
- END RequestAuthorizeKey;
- PROCEDURE AuthorizeKey( ssh: Connection; CONST user: ARRAY OF CHAR ): BOOLEAN;
- CONST
- headline = "enter passphrase for opening your private key";
- VAR
- f: Files.File; r: Files.Reader; i: LONGINT;
- pw: ARRAY 64 OF CHAR;
- BEGIN
- IF privKey = NIL THEN
- f := Files.Old( G.PrivateKeyFile );
- IF f = NIL THEN
- Out.String( "private key '" ); Out.String( G.PrivateKeyFile );
- Out.String( "' not found" ); Out.Ln;
- RETURN FALSE
- END;
- Files.OpenReader( r, f, 0 ); i := 0;
- REPEAT
- Beep.Beep( 1000 );
- IGNORE WMDialogs.QueryPassword( headline, pw );
- r.SetPos( 0 );
- privKey := RSA.LoadPrivateKey( r, pw );
- INC( i )
- UNTIL (privKey # NIL) OR (i = 2);
- IF privKey = NIL THEN
- Out.String( "### error: wrong passphrase" ); Out.Ln; RETURN FALSE
- END;
- END;
- f := Files.Old( G.PublicKeyFile );
- IF f = NIL THEN
- Out.String( "### error: public key not found" ); Out.Ln;
- RETURN FALSE
- END;
- Files.OpenReader( r, f, 0 );
- pubKey := RSA.LoadPublicKey( r );
- IF CheckAuthorizeKey( ssh, user ) THEN
- RETURN RequestAuthorizeKey( ssh, user )
- END;
- RETURN FALSE
- END AuthorizeKey;
- (** Open an outhorized SSH connection, returns NIL on failure *)
- PROCEDURE OpenConnection*( CONST host, user: ARRAY OF CHAR ): Connection;
- VAR
- ssh: Connection; authorized: BOOLEAN;
- BEGIN
- NEW( ssh, host );
- IF ssh.state = Connected THEN
- IF RequestService( ssh, "ssh-userauth" ) THEN
- authorized := RequestAuthorizeNone( ssh, user );
- IF ~authorized THEN
- Out.String( "trying public key authentication" ); Out.Ln;
- authorized := AuthorizeKey( ssh, user );
- END;
- IF ~authorized THEN
- Out.String( "trying password authentication" ); Out.Ln;
- authorized := AuthorizePasswd( ssh, host, user )
- END;
- IF ~authorized THEN
- ssh.Disconnect( 11, "" ); RETURN NIL
- END;
- RETURN ssh
- ELSE
- RETURN NIL
- END
- ELSE
- RETURN NIL
- END
- END OpenConnection;
- END SSHAuthorize.
|