diff --git a/README.md b/README.md index 663a85a..b9e8d59 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,7 @@ -# abapGit-ssh -testing test +# open-abap-ssh +SSH client implemented in ABAP, over TCP/IP with 1 byte frame sizes = slow. + +https://datatracker.ietf.org/doc/html/rfc4251 - The Secure Shell (SSH) Protocol Architecture +https://datatracker.ietf.org/doc/html/rfc4252 - The Secure Shell (SSH) Authentication Protocol +https://datatracker.ietf.org/doc/html/rfc4253 - The Secure Shell (SSH) Transport Layer Protocol +https://datatracker.ietf.org/doc/html/rfc4254 - The Secure Shell (SSH) Connection Protocol \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 343414c..8a998db 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,15 +9,15 @@ "version": "1.0.0", "license": "MIT", "dependencies": { - "@abaplint/cli": "^2.85.32", - "@abaplint/runtime": "^1.8.11", - "@abaplint/transpiler-cli": "^1.8.11" + "@abaplint/cli": "^2.89.0", + "@abaplint/runtime": "^2.0.9", + "@abaplint/transpiler-cli": "^2.0.9" } }, "node_modules/@abaplint/cli": { - "version": "2.85.32", - "resolved": "https://registry.npmjs.org/@abaplint/cli/-/cli-2.85.32.tgz", - "integrity": "sha512-GBtpn6JGNkwBH48g1ZhARW31ZQdn4hrohcYug16NZPUwfbkDOBCZEMDWOOnQO/wfmitlaRktUEID6W+lbkTgAQ==", + "version": "2.89.0", + "resolved": "https://registry.npmjs.org/@abaplint/cli/-/cli-2.89.0.tgz", + "integrity": "sha512-N+qpOa1BkHDglX4ibITrxpJvRN3JIesRumuePMDPkee2bqNfDfgq6xZedLoWI2kUsAj5DpiWdKbNY4nBme0WIg==", "bin": { "abaplint": "abaplint" }, @@ -26,100 +26,34 @@ } }, "node_modules/@abaplint/runtime": { - "version": "1.8.11", - "resolved": "https://registry.npmjs.org/@abaplint/runtime/-/runtime-1.8.11.tgz", - "integrity": "sha512-c35VaQ+vNEHRQ0RBVEvgceHbnRuRlPxUtrg73y5tFT3j34K7KF8k6nOIaZqotH4gnraWcDDEfjxUCWy0tQAVzQ==", - "dependencies": { - "hdb": "^0.19.1", - "sql.js": "^1.6.2" - } + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@abaplint/runtime/-/runtime-2.0.9.tgz", + "integrity": "sha512-z6jIDF/98+DAVDdM5LYeBNLIJrh4Mg/EIa3C+ESCokLevGMCTynuGomg3E8mv9/Cu+YxWA0SPMzcGof0i7jg7Q==" }, "node_modules/@abaplint/transpiler-cli": { - "version": "1.8.11", - "resolved": "https://registry.npmjs.org/@abaplint/transpiler-cli/-/transpiler-cli-1.8.11.tgz", - "integrity": "sha512-JlENFEvzRraJxEPYKMXPgLZX/clH5hSGFyttKMPGUREX7qg6OS99lMSGCKF2TisyS0GAW38N+jIcs2dVTYn5jw==", + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@abaplint/transpiler-cli/-/transpiler-cli-2.0.9.tgz", + "integrity": "sha512-1prLaF03TqQ5OAndGt1BhmUQXjw9Ip0HKVWftyjc7KvFq2P/QscLqB5EuLiOnzIOKnBFt6bb6CLJgFTNRJTdWw==", "bin": { "abap_transpile": "abap_transpile" } - }, - "node_modules/hdb": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/hdb/-/hdb-0.19.1.tgz", - "integrity": "sha512-QqB7Srj/AaesB1bZPiKZMPXnjU4NRgP7ZheCHUWf4EKKqZXpWW2lJcb6BRnNfjxfCYIT+TR1wIaA0zLO1CeU6w==", - "dependencies": { - "iconv-lite": "^0.4.18" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/sql.js": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/sql.js/-/sql.js-1.6.2.tgz", - "integrity": "sha512-9iucI5fXQa+Gspeqf/BNB20PxJIn5LhXDt4mjXoFPqXdR+NqtFs15SdKpSIJ6s529aGL9zFR9p2eSCIEiMsNGA==" } }, "dependencies": { "@abaplint/cli": { - "version": "2.85.32", - "resolved": "https://registry.npmjs.org/@abaplint/cli/-/cli-2.85.32.tgz", - "integrity": "sha512-GBtpn6JGNkwBH48g1ZhARW31ZQdn4hrohcYug16NZPUwfbkDOBCZEMDWOOnQO/wfmitlaRktUEID6W+lbkTgAQ==" + "version": "2.89.0", + "resolved": "https://registry.npmjs.org/@abaplint/cli/-/cli-2.89.0.tgz", + "integrity": "sha512-N+qpOa1BkHDglX4ibITrxpJvRN3JIesRumuePMDPkee2bqNfDfgq6xZedLoWI2kUsAj5DpiWdKbNY4nBme0WIg==" }, "@abaplint/runtime": { - "version": "1.8.11", - "resolved": "https://registry.npmjs.org/@abaplint/runtime/-/runtime-1.8.11.tgz", - "integrity": "sha512-c35VaQ+vNEHRQ0RBVEvgceHbnRuRlPxUtrg73y5tFT3j34K7KF8k6nOIaZqotH4gnraWcDDEfjxUCWy0tQAVzQ==", - "requires": { - "hdb": "^0.19.1", - "sql.js": "^1.6.2" - } + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@abaplint/runtime/-/runtime-2.0.9.tgz", + "integrity": "sha512-z6jIDF/98+DAVDdM5LYeBNLIJrh4Mg/EIa3C+ESCokLevGMCTynuGomg3E8mv9/Cu+YxWA0SPMzcGof0i7jg7Q==" }, "@abaplint/transpiler-cli": { - "version": "1.8.11", - "resolved": "https://registry.npmjs.org/@abaplint/transpiler-cli/-/transpiler-cli-1.8.11.tgz", - "integrity": "sha512-JlENFEvzRraJxEPYKMXPgLZX/clH5hSGFyttKMPGUREX7qg6OS99lMSGCKF2TisyS0GAW38N+jIcs2dVTYn5jw==" - }, - "hdb": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/hdb/-/hdb-0.19.1.tgz", - "integrity": "sha512-QqB7Srj/AaesB1bZPiKZMPXnjU4NRgP7ZheCHUWf4EKKqZXpWW2lJcb6BRnNfjxfCYIT+TR1wIaA0zLO1CeU6w==", - "requires": { - "iconv-lite": "^0.4.18" - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "sql.js": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/sql.js/-/sql.js-1.6.2.tgz", - "integrity": "sha512-9iucI5fXQa+Gspeqf/BNB20PxJIn5LhXDt4mjXoFPqXdR+NqtFs15SdKpSIJ6s529aGL9zFR9p2eSCIEiMsNGA==" + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@abaplint/transpiler-cli/-/transpiler-cli-2.0.9.tgz", + "integrity": "sha512-1prLaF03TqQ5OAndGt1BhmUQXjw9Ip0HKVWftyjc7KvFq2P/QscLqB5EuLiOnzIOKnBFt6bb6CLJgFTNRJTdWw==" } } } diff --git a/package.json b/package.json index bae75e4..14f787a 100644 --- a/package.json +++ b/package.json @@ -18,8 +18,8 @@ }, "homepage": "https://github.com/open-abap/open-abap-ssh#readme", "dependencies": { - "@abaplint/cli": "^2.85.32", - "@abaplint/runtime": "^1.8.11", - "@abaplint/transpiler-cli": "^1.8.11" + "@abaplint/cli": "^2.89.0", + "@abaplint/runtime": "^2.0.9", + "@abaplint/transpiler-cli": "^2.0.9" } } diff --git a/src/zcl_oassh.clas.abap b/src/zcl_oassh.clas.abap index d58e844..b527908 100644 --- a/src/zcl_oassh.clas.abap +++ b/src/zcl_oassh.clas.abap @@ -21,10 +21,12 @@ CLASS zcl_oassh DEFINITION key_exchange TYPE i VALUE 2, END OF gc_state . DATA mi_client TYPE REF TO if_apc_wsp_client . - DATA mv_buffer TYPE xstring . + DATA mo_stream TYPE REF TO zcl_oassh_stream . DATA mv_state TYPE i . - METHODS handle . + METHODS handle + RAISING + cx_apc_error . METHODS send IMPORTING !iv_message TYPE xstring @@ -34,7 +36,7 @@ ENDCLASS. -CLASS zcl_oassh IMPLEMENTATION. +CLASS ZCL_OASSH IMPLEMENTATION. METHOD connect. @@ -44,6 +46,8 @@ CLASS zcl_oassh IMPLEMENTATION. CREATE OBJECT lo_ssh. + CREATE OBJECT lo_ssh->mo_stream. + ls_frame-frame_type = if_apc_tcp_frame_types=>co_frame_type_fixed_length. ls_frame-fixed_length = 1. @@ -61,30 +65,31 @@ CLASS zcl_oassh IMPLEMENTATION. METHOD handle. DATA lv_remote_version TYPE string. - DATA lo_stream TYPE REF TO zcl_oassh_stream. DATA lv_padding_length TYPE i. DATA lv_length TYPE i. DATA ls_kexinit TYPE zcl_oassh_message_20=>ty_data. CASE mv_state. WHEN gc_state-protocol_version_exchange. - IF mv_buffer CP |*{ cl_abap_codepage=>convert_to( |{ cl_abap_char_utilities=>cr_lf }| ) }|. - lv_remote_version = cl_abap_codepage=>convert_from( mv_buffer ). - CLEAR mv_buffer. + IF mo_stream->get( ) CP |*{ cl_abap_codepage=>convert_to( |{ cl_abap_char_utilities=>cr_lf }| ) }|. + lv_remote_version = cl_abap_codepage=>convert_from( mo_stream->get( ) ). + mo_stream->clear( ). mv_state = gc_state-key_exchange. ENDIF. WHEN gc_state-key_exchange. -* todo, check buffer contains a full packet, and return the packet payload * https://datatracker.ietf.org/doc/html/rfc4253#section-7 - IF xstrlen( mv_buffer ) > 4. - CREATE OBJECT lo_stream EXPORTING iv_hex = mv_buffer. - lv_length = lo_stream->uint32_decode( ). - IF lo_stream->get_length( ) = lv_length. + IF mo_stream->get_length( ) > 4. + lv_length = mo_stream->uint32_decode_peek( ). + IF mo_stream->get_length( ) = lv_length. + mo_stream->uint32_decode( ). * there is no MAC negotiated at this point in time - lv_padding_length = lo_stream->take( 1 ). - ls_kexinit = zcl_oassh_message_20=>parse( lo_stream ). - lo_stream->take( lv_padding_length ). + lv_padding_length = mo_stream->take( 1 ). + ls_kexinit = zcl_oassh_message_20=>parse( mo_stream ). + mo_stream->take( lv_padding_length / 2 ). + + ls_kexinit-cookie = '11223344556677881122334455667788'. " todo, this should value should be random + send( zcl_oassh_message_20=>serialize( ls_kexinit )->get( ) ). ENDIF. ENDIF. @@ -94,11 +99,13 @@ CLASS zcl_oassh IMPLEMENTATION. METHOD if_apc_wsp_event_handler~on_close. + BREAK-POINT. WRITE / 'on_close'. ENDMETHOD. METHOD if_apc_wsp_event_handler~on_error. + BREAK-POINT. WRITE / 'on_error'. ENDMETHOD. @@ -108,17 +115,17 @@ CLASS zcl_oassh IMPLEMENTATION. TRY. lv_message = i_message->get_binary( ). - CATCH cx_root. + mo_stream->append( lv_message ). + handle( ). + CATCH cx_root INTO DATA(lx_error). + BREAK-POINT. ENDTRY. - mv_buffer = mv_buffer && lv_message. - - handle( ). - ENDMETHOD. METHOD if_apc_wsp_event_handler~on_open. DATA lv_xstr TYPE xstring. + BREAK-POINT. WRITE / 'on_open'. @@ -141,8 +148,8 @@ CLASS zcl_oassh IMPLEMENTATION. DATA li_message_manager TYPE REF TO if_apc_wsp_message_manager. DATA li_message TYPE REF TO if_apc_wsp_message. - DATA lv_index TYPE i. - DATA lv_hex TYPE xstring. + DATA lv_index TYPE i. + DATA lv_hex TYPE xstring. li_message_manager ?= mi_client->get_message_manager( ). @@ -158,4 +165,4 @@ CLASS zcl_oassh IMPLEMENTATION. ENDDO. ENDMETHOD. -ENDCLASS. \ No newline at end of file +ENDCLASS. diff --git a/src/zcl_oassh.clas.xml b/src/zcl_oassh.clas.xml index 0aa13ed..6982130 100644 --- a/src/zcl_oassh.clas.xml +++ b/src/zcl_oassh.clas.xml @@ -5,7 +5,7 @@ ZCL_OASSH E - ssh test + open-abap-ssh 1 X X diff --git a/src/zcl_oassh_message_20.clas.abap b/src/zcl_oassh_message_20.clas.abap index f5909ba..1589e81 100644 --- a/src/zcl_oassh_message_20.clas.abap +++ b/src/zcl_oassh_message_20.clas.abap @@ -43,10 +43,12 @@ ENDCLASS. -CLASS ZCL_OASSH_MESSAGE_20 IMPLEMENTATION. +CLASS zcl_oassh_message_20 IMPLEMENTATION. METHOD parse. +* https://datatracker.ietf.org/doc/html/rfc4253#section-7.1 +* SSH_MSG_KEXINIT rs_data-message_id = io_stream->take( 1 ). ASSERT rs_data-message_id = gc_message_id. diff --git a/src/zcl_oassh_message_ecdh_30.clas.abap b/src/zcl_oassh_message_ecdh_30.clas.abap new file mode 100644 index 0000000..6e633e7 --- /dev/null +++ b/src/zcl_oassh_message_ecdh_30.clas.abap @@ -0,0 +1,45 @@ +CLASS zcl_oassh_message_ecdh_30 DEFINITION + PUBLIC + FINAL + CREATE PUBLIC . + + PUBLIC SECTION. + + TYPES: + BEGIN OF ty_data, + message_id TYPE x LENGTH 1, + q_c TYPE xstring, + END OF ty_data . + + CONSTANTS gc_message_id TYPE x LENGTH 1 VALUE '1E'. " is 30 in decimal + + CLASS-METHODS parse + IMPORTING + !io_stream TYPE REF TO zcl_oassh_stream + RETURNING + VALUE(rs_data) TYPE ty_data . + + CLASS-METHODS serialize + IMPORTING + is_data TYPE ty_data + RETURNING + VALUE(ro_stream) TYPE REF TO zcl_oassh_stream . + + PROTECTED SECTION. + PRIVATE SECTION. +ENDCLASS. + + + +CLASS ZCL_OASSH_MESSAGE_ECDH_30 IMPLEMENTATION. + + + METHOD parse. + BREAK-POINT. + ENDMETHOD. + + + METHOD serialize. + BREAK-POINT. + ENDMETHOD. +ENDCLASS. diff --git a/src/zcl_oassh_message_ecdh_30.clas.xml b/src/zcl_oassh_message_ecdh_30.clas.xml new file mode 100644 index 0000000..bd510a6 --- /dev/null +++ b/src/zcl_oassh_message_ecdh_30.clas.xml @@ -0,0 +1,16 @@ + + + + + + ZCL_OASSH_MESSAGE_ECDH_30 + E + SSH_MSG_KEX_ECDH_INIT + 1 + X + X + X + + + + diff --git a/src/zcl_oassh_message_ecdh_31.clas.abap b/src/zcl_oassh_message_ecdh_31.clas.abap new file mode 100644 index 0000000..c068aac --- /dev/null +++ b/src/zcl_oassh_message_ecdh_31.clas.abap @@ -0,0 +1,47 @@ +CLASS zcl_oassh_message_ecdh_31 DEFINITION + PUBLIC + FINAL + CREATE PUBLIC . + + PUBLIC SECTION. + + TYPES: + BEGIN OF ty_data, + message_id TYPE x LENGTH 1, + k_s TYPE xstring, + q_s TYPE xstring, + signature TYPE xstring, + END OF ty_data . + + CONSTANTS gc_message_id TYPE x LENGTH 1 VALUE '1F'. " is 31 in decimal + + CLASS-METHODS parse + IMPORTING + !io_stream TYPE REF TO zcl_oassh_stream + RETURNING + VALUE(rs_data) TYPE ty_data . + + CLASS-METHODS serialize + IMPORTING + is_data TYPE ty_data + RETURNING + VALUE(ro_stream) TYPE REF TO zcl_oassh_stream . + + PROTECTED SECTION. + PRIVATE SECTION. +ENDCLASS. + + + +CLASS ZCL_OASSH_MESSAGE_ECDH_31 IMPLEMENTATION. + + + METHOD parse. + BREAK-POINT. + ENDMETHOD. + + + METHOD serialize. + BREAK-POINT. + ENDMETHOD. +ENDCLASS. diff --git a/src/zcl_oassh_message_ecdh_31.clas.xml b/src/zcl_oassh_message_ecdh_31.clas.xml new file mode 100644 index 0000000..b9cab9e --- /dev/null +++ b/src/zcl_oassh_message_ecdh_31.clas.xml @@ -0,0 +1,16 @@ + + + + + + ZCL_OASSH_MESSAGE_ECDH_31 + E + SSH_MSG_KEX_ECDH_REPLY + 1 + X + X + X + + + + diff --git a/src/zcl_oassh_stream.clas.abap b/src/zcl_oassh_stream.clas.abap index 226d263..22f6530 100644 --- a/src/zcl_oassh_stream.clas.abap +++ b/src/zcl_oassh_stream.clas.abap @@ -37,12 +37,23 @@ CLASS zcl_oassh_stream DEFINITION METHODS uint32_decode RETURNING VALUE(rv_int) TYPE i . + METHODS uint32_decode_peek + RETURNING + VALUE(rv_int) TYPE i . METHODS get_length RETURNING VALUE(rv_length) TYPE i . + METHODS clear . + METHODS string_encode + IMPORTING + !iv_string TYPE xstring . + METHODS string_decode + RETURNING + VALUE(rv_string) TYPE xstring . PROTECTED SECTION. PRIVATE SECTION. - DATA mv_hex TYPE xstring. + + DATA mv_hex TYPE xstring . ENDCLASS. @@ -72,6 +83,11 @@ CLASS ZCL_OASSH_STREAM IMPLEMENTATION. ENDMETHOD. + METHOD clear. + CLEAR mv_hex. + ENDMETHOD. + + METHOD constructor. mv_hex = iv_hex. ENDMETHOD. @@ -115,6 +131,26 @@ CLASS ZCL_OASSH_STREAM IMPLEMENTATION. ENDMETHOD. + METHOD string_decode. +* https://datatracker.ietf.org/doc/html/rfc4251#section-5 + + DATA lv_len TYPE i. + + lv_len = uint32_decode( ). + rv_string = take( lv_len ). + + ENDMETHOD. + + + METHOD string_encode. +* https://datatracker.ietf.org/doc/html/rfc4251#section-5 + + uint32_encode( xstrlen( iv_string ) ). + append( iv_string ). + + ENDMETHOD. + + METHOD take. rv_hex = mv_hex(iv_length). mv_hex = mv_hex+iv_length. @@ -128,6 +164,13 @@ CLASS ZCL_OASSH_STREAM IMPLEMENTATION. ENDMETHOD. + METHOD uint32_decode_peek. + + rv_int = mv_hex(4). + + ENDMETHOD. + + METHOD uint32_encode. DATA lv_hex TYPE x LENGTH 4. diff --git a/src/zcl_oassh_stream.clas.xml b/src/zcl_oassh_stream.clas.xml index b49d204..76b9ae6 100644 --- a/src/zcl_oassh_stream.clas.xml +++ b/src/zcl_oassh_stream.clas.xml @@ -5,7 +5,7 @@ ZCL_OASSH_STREAM E - Stream + open-abap-ssh - Stream 1 X X