@@ -171,7 +171,8 @@ def extract_args(untrusted_line: bytes, sep: bytes = b' ') -> Tuple[bytes, Optio
171171 return untrusted_line , None
172172
173173# none of our uses allow 0, so do not allow it
174- _int_re = re .compile (rb'\A[1-9][0-9]*\Z' )
174+ _int_re : re .Pattern [bytes ] = re .compile (rb'\A[1-9][0-9]*\Z' )
175+ _hash_regex = re .compile (rb'\A[0-9A-F]+\Z' )
175176
176177def sanitize_int (untrusted_arg : bytes , min_value : int , max_value : int ) -> int :
177178 """
@@ -224,6 +225,8 @@ class GpgServer:
224225 log : logging .Logger
225226
226227 cache_nonce_regex : re .Pattern [bytes ] = re .compile (rb'\A[0-9A-F]{24}\Z' )
228+ # Any command argument ever sent to the agent should match this pattern.
229+ command_argument_regex : re .Pattern [bytes ] = re .compile (rb'\A[0-9A-Za-z_=. -]*\Z' )
227230
228231 __slots__ = ('verbose_notifications' ,
229232 'timer_delay' ,
@@ -640,15 +643,15 @@ def fake_respond(self, response: bytes) -> None:
640643
641644 @staticmethod
642645 def verify_keygrip_arguments (min_count : int , max_count : int ,
643- untrusted_args : Optional [bytes ]) -> bytes :
646+ untrusted_args : Optional [bytes ]) -> bytes :
644647 if untrusted_args is None :
645648 raise Filtered
646- args_regex = re .compile (rb'\A[0-9A-F]{40}( [0-9A-F]{40}){%d,%d}\Z' %
647- (min_count - 1 , max_count - 1 ))
648-
649- if args_regex .match (untrusted_args ) is None :
649+ if not (min_count <= len (untrusted_args_list ) <= max_count ):
650650 raise Filtered
651- return untrusted_args
651+ for untrusted_arg in untrusted_args_list :
652+ if len (untrusted_arg ) != 40 or not _hash_regex .match (untrusted_arg ):
653+ raise Filtered
654+ return b' ' .join (untrusted_args_list )
652655
653656 def sanitize_key_desc (self , untrusted_args : bytes ) -> bytes :
654657 untrusted_args = untrusted_args .replace (b'+' , b' ' )
@@ -937,30 +940,27 @@ async def command_SETHASH(self, untrusted_args: Optional[bytes]) -> None:
937940 except KeyError as e :
938941 raise Filtered from e
939942
940- if not untrusted_hash :
943+ if len ( untrusted_hash ) != alg_param . len :
941944 raise Filtered
942945
943- hash_regex = re .compile (rb'\A[0-9A-F]{%d}\Z' % alg_param .len )
944- if hash_regex .match (untrusted_hash ) is None :
946+ if not _hash_regex .match (untrusted_hash ):
945947 raise Filtered
946948 hash_value = untrusted_hash
947949
948- await self . send_agent_command (
949- b'SETHASH' , b'%d %s' % (alg , hash_value ))
950+ # Hash values and ASCII decimal numbers are safe to pass.
951+ await self . send_agent_command ( b'SETHASH' , b'%d %s' % (alg , hash_value ))
950952
951953 async def command_PKSIGN (self , untrusted_args : Optional [bytes ]) -> None :
952954 if untrusted_args is not None :
953955 if not untrusted_args .startswith (b'-- ' ):
954956 raise Filtered
955- untrusted_args = untrusted_args [3 :]
956- if self .cache_nonce_regex .match (untrusted_args ) is None :
957+ if self .cache_nonce_regex .match (untrusted_args [3 :]) is None :
957958 raise Filtered
958- args = b'-- ' + untrusted_args
959- else :
960- args = None
959+ args = untrusted_args
961960
962961 self .request_timer ('PKSIGN' )
963962
963+ # String checked to be '-- ' followed by a cache nonce
964964 await self .send_agent_command (b'PKSIGN' , args )
965965
966966 async def command_GETINFO (self , untrusted_args : Optional [bytes ]) -> None :
@@ -1019,6 +1019,8 @@ async def send_agent_command(self, command: bytes, args: Optional[bytes]) -> Non
10191019 """ Sends command to local gpg agent and handle the response """
10201020 expected_inquires = self .get_inquires_for_command (command )
10211021 if args :
1022+ if not self .command_argument_regex .match (args ):
1023+ raise AssertionError ("BUG: corrupt command about to be sent to agent!" )
10221024 cmd_with_args = command + b' ' + args + b'\n '
10231025 else :
10241026 cmd_with_args = command + b'\n '
@@ -1355,7 +1357,7 @@ def _parse_sexpr(cls, untrusted_arg: bytes, nesting: int) -> Tuple[List['SExpr']
13551357
13561358 rest : bytes
13571359 value : Union [List ['SExpr' ], bytes ]
1358- if untrusted_arg [0 ] in range ( 0x30 , 0x40 ) :
1360+ if 0x30 <= untrusted_arg [0 ] <= 0x40 :
13591361 length_s , rest = untrusted_arg .split (b':' , 1 )
13601362 length = sanitize_int (length_s , 1 , len (rest ))
13611363 value , rest = rest [0 :length ], rest [length :]
0 commit comments