diff --git a/mock_ca/nested_handler.py b/mock_ca/nested_handler.py index 4a97cf99..bbe62371 100644 --- a/mock_ca/nested_handler.py +++ b/mock_ca/nested_handler.py @@ -319,5 +319,6 @@ def process_batched_request( recip_nonce=request["header"]["senderNonce"].asOctets(), sender=prot_handler.sender, recipient=request["header"]["sender"], + pvno=request["header"]["pvno"], ) return prot_handler.protect_pkimessage(response=pki_message, request=request) diff --git a/tests/pki_mgmt_entity_op.robot b/tests/pki_mgmt_entity_op.robot index b4007c4d..9ede7112 100644 --- a/tests/pki_mgmt_entity_op.robot +++ b/tests/pki_mgmt_entity_op.robot @@ -194,6 +194,28 @@ CA MUST Respond with MAC To Added Protection For MAC Inner Request Fail The response to the wrapped protected message was not MAC-based protected. END +CA MUST Respond with A Correct PVNO For Inner Added Protection + [Documentation] According to RFC 9483 Section 3.1 and RFC 9480 Section 7 the `pvno` field in the header of a + ... PKIMessage MUST be set to the request message's `pvno` value when the response is returned. We send a + ... added protection nested PKIMessage with pvno set to 2 and a inner PKIMessage with pvno set to 3. The CA + ... MUST respond with a message that has the `pvno` value set to 3. + [Tags] adding-protection nested positive added-protection pvno + Skip If Cert Or Key Not Set + ${protected_ir}= Default Build Inner IR Message pvno=3 + ${nested}= Build Nested PKIMessage + ... exclude_fields=${None} + ... sender=${SENDER} + ... recipient=${RECIPIENT} + ... other_messages=${protected_ir} + ... for_added_protection=True + ... pvno=3 + ${prot_nested}= Default Protect With Trusted Cert ${nested} + ${response}= Exchange PKIMessage ${prot_nested} + PKIMessage Body Type Must Be ${response} ip + PKIStatus Must Be ${response} status=accepted + ${response_pvno}= Get Asn1 Value As Number ${response} header.pvno + Should Be Equal As Integers ${response_pvno} 3 + ## Section 5.2.2.2. Batching Messages CA MUST Accept Valid Nested Batch Message @@ -263,6 +285,112 @@ CA MUST Check The Protection Of All Inner Messages PKIStatus Must Be ${response} status=rejection PKIStatusInfo Failinfo Bit Must Be ${response} failinfo=badMessageCheck exclusive=True +CA MUST Respond With Correct PVNO For Outer And Inner Batch Message + [Documentation] According to RFC 9483 Section 3.1 and RFC 9480 Section 7, the `pvno` field in the + ... response MUST match the `pvno` of the corresponding request. We send a nested batch PKIMessage + ... where the outer message has `pvno` set to 3 and all three inner IR messages have `pvno` set to 2. + ... The CA MUST respond with a nested message where the outer response has `pvno` 3 and each inner + ... `ip` response has `pvno` 2. + [Tags] batching nested positive batch pvno + Skip If Cert Or Key Not Set + ${nonces}= Generate Unique Byte Values length=4 + ${ids}= Generate Unique Byte Values length=4 + VAR @{inner_irs} + FOR ${i} IN RANGE 3 + ${ir}= Default Build Inner IR Message + ... pvno=2 + ... transaction_id=${ids}[${i}] + ... sender_nonce=${nonces}[${i}] + Append To List ${inner_irs} ${ir} + END + ${nested}= Build Nested PKIMessage + ... recipient=${RECIPIENT} + ... other_messages=${inner_irs} + ... sender_nonce=${nonces}[3] + ... transaction_id=${ids}[3] + ... pvno=3 + ${prot_nested}= Default Protect With Trusted Cert ${nested} + ${response}= Exchange PKIMessage ${prot_nested} + PKIMessage Body Type Must Be ${response} nested + ${outer_pvno}= Get Asn1 Value As Number ${response} header.pvno + Should Be Equal As Integers ${outer_pvno} 3 + FOR ${i} IN RANGE 3 + ${inner_response}= Get Inner PKIMessage ${response} index=${i} + ${inner_pvno}= Get Asn1 Value As Number ${inner_response} header.pvno + Should Be Equal As Integers ${inner_pvno} 2 + END + +CA MUST Respond With Correct PVNO For Outer And Inner Batch Message Reversed + [Documentation] According to RFC 9483 Section 3.1 and RFC 9480 Section 7, the `pvno` field in the + ... response MUST match the `pvno` of the corresponding request. We send a nested batch PKIMessage + ... where the outer message has `pvno` set to 2 and all three inner IR messages have `pvno` set to 3. + ... The CA MUST respond with a nested message where the outer response has `pvno` 2 and each inner + ... `ip` response has `pvno` 3. + [Tags] batching nested positive batch pvno + Skip If Cert Or Key Not Set + ${nonces}= Generate Unique Byte Values length=4 + ${ids}= Generate Unique Byte Values length=4 + VAR @{inner_irs} + FOR ${i} IN RANGE 3 + ${ir}= Default Build Inner IR Message + ... pvno=3 + ... transaction_id=${ids}[${i}] + ... sender_nonce=${nonces}[${i}] + Append To List ${inner_irs} ${ir} + END + ${nested}= Build Nested PKIMessage + ... recipient=${RECIPIENT} + ... other_messages=${inner_irs} + ... sender_nonce=${nonces}[3] + ... transaction_id=${ids}[3] + ... pvno=2 + ${prot_nested}= Default Protect With Trusted Cert ${nested} + ${response}= Exchange PKIMessage ${prot_nested} + PKIMessage Body Type Must Be ${response} nested + ${outer_pvno}= Get Asn1 Value As Number ${response} header.pvno + Should Be Equal As Integers ${outer_pvno} 2 + FOR ${i} IN RANGE 3 + ${inner_response}= Get Inner PKIMessage ${response} index=${i} + ${inner_pvno}= Get Asn1 Value As Number ${inner_response} header.pvno + Should Be Equal As Integers ${inner_pvno} 3 + END + +CA MUST Respond With Correct PVNO For Outer And Inner Batch Message Mixed + [Documentation] According to RFC 9483 Section 3.1 and RFC 9480 Section 7, the `pvno` field in the + ... response MUST match the `pvno` of the corresponding request. We send a nested batch PKIMessage + ... where the outer message has `pvno` set to 3 and three inner IR messages have `pvno` set to 2, 3, and 2. + ... The CA MUST respond with a nested message where the outer response has `pvno` 3 and each inner + ... `ip` response has the corresponding `pvno` (2, 3, 2). + [Tags] batching nested positive batch pvno + Skip If Cert Or Key Not Set + ${nonces}= Generate Unique Byte Values length=4 + ${ids}= Generate Unique Byte Values length=4 + VAR @{inner_irs} + VAR @{expected_pvnos} ${2} ${3} ${2} + FOR ${i} IN RANGE 3 + ${ir}= Default Build Inner IR Message + ... pvno=${expected_pvnos}[${i}] + ... transaction_id=${ids}[${i}] + ... sender_nonce=${nonces}[${i}] + Append To List ${inner_irs} ${ir} + END + ${nested}= Build Nested PKIMessage + ... recipient=${RECIPIENT} + ... other_messages=${inner_irs} + ... sender_nonce=${nonces}[3] + ... transaction_id=${ids}[3] + ... pvno=3 + ${prot_nested}= Default Protect With Trusted Cert ${nested} + ${response}= Exchange PKIMessage ${prot_nested} + PKIMessage Body Type Must Be ${response} nested + ${outer_pvno}= Get Asn1 Value As Number ${response} header.pvno + Should Be Equal As Integers ${outer_pvno} 3 + FOR ${i} IN RANGE 3 + ${inner_response}= Get Inner PKIMessage ${response} index=${i} + ${inner_pvno}= Get Asn1 Value As Number ${inner_response} header.pvno + Should Be Equal As Integers ${inner_pvno} ${expected_pvnos}[${i}] + END + ### Section 5.2.3 Replacing Protection # According to Section 5.2.3, when an intermediate PKI management entity modifies a message, diff --git a/unit_tests/tests_experimental_and_mock_ca/tests_mock_ca/test_process_batch_message.py b/unit_tests/tests_experimental_and_mock_ca/tests_mock_ca/test_process_batch_message.py index 146be0fc..5ec08f96 100644 --- a/unit_tests/tests_experimental_and_mock_ca/tests_mock_ca/test_process_batch_message.py +++ b/unit_tests/tests_experimental_and_mock_ca/tests_mock_ca/test_process_batch_message.py @@ -55,6 +55,7 @@ def _generate_nested_message( sender_nonce=sender_nonce[0], recip_nonce=recip_nonce[0] if include_recip_nonce else None, for_mac=True, + pvno=2 ) ir = build_ir_from_key( @@ -82,6 +83,7 @@ def _generate_nested_message( transaction_id=trans_id[2], sender_nonce=sender_nonce[2], recip_nonce=recip_nonce[2] if include_recip_nonce else None, + pvno=3 ) return protect_pkimessage( pki_message=nested, @@ -93,6 +95,7 @@ def _generate_nested_message( def test_process_batch_message(self): """Test processing a batch message.""" nested = self._generate_nested_message(False, False) + self.assertEqual(3, int(nested["header"]["pvno"])) self.assertEqual(nested["body"].getName(), "nested") self.assertEqual(len(nested["body"]["nested"]), 2) self.assertEqual(nested["body"]["nested"][0]["body"].getName(), "ir") @@ -105,6 +108,7 @@ def test_process_batch_message(self): self.assertEqual(response["body"]["nested"][0]["header"]["protectionAlg"]["algorithm"], rfc9481.id_PBMAC1) self.assertEqual(response["body"]["nested"][1]["header"]["protectionAlg"]["algorithm"], rfc9481.id_PBMAC1) + self.assertEqual(3, int(response["header"]["pvno"])) def test_process_batch_message_bad_message_check(self): """Test processing a batch message with bad message check.""" @@ -118,3 +122,7 @@ def test_process_batch_message_bad_message_check(self): texts = [x.prettyPrint() for x in pki_status_info["statusString"]] self.assertIn("Invalid inner batch PKIMessage protection at index 1.", texts) + + +if __name__ == "__main__": + unittest.main() \ No newline at end of file