Generic remote attestation implementation#148
Conversation
da71f21 to
86b8402
Compare
0814d99 to
0e2e343
Compare
bbab075 to
812c16d
Compare
|
| EvidenceBundle evidenceBundle = EvidenceBundle.getInstance(evidenceItav.getParsedValue()); | ||
| EvidenceStatement[] evidences = evidenceBundle.getEvidences(); | ||
| AttestationResult[] attestationResults = new AttestationResult[evidences.length]; |
There was a problem hiding this comment.
Would it be feasible for an attacker to craft a message that makes it look like evidences.length is a very large number?
There was a problem hiding this comment.
Yes, but ASN.1 is unlimited too.
There was a problem hiding this comment.
TODO consider writing some tests to check if BouncyCastle itself will take care of such malicious payloads.
There was a problem hiding this comment.
I think the worst thing that could happen here is a OutOfMemoryError exception, right?
If so, at which level would it be caught and handled?
| NonceRequest aktRequest = nonceRequests[i]; | ||
| NonceResponseRet ret = verifyAdapter.generateNonce( | ||
| msg.getHeader().getTransactionID().getOctets(), | ||
| ifNotNull(aktRequest.getLen(), ASN1Integer::getValue), |
There was a problem hiding this comment.
Would it make sense to set an upper bound to the size of the nonce we generate?
ASN1 Integers are essentially unbounded, so a specially crafted request could potentially exhaust our memory.
There was a problem hiding this comment.
If the nonce must be PQ-safe it could become bigger :-)
There was a problem hiding this comment.
@ralienpp is right, an attacker could easily provoke an out-of-memory condition and thus do a DoS attack.
Clearly the size of the nonces should be limited to a sensible value.
|
Additional recommended reading material: RFC 9334, esp. section 5.2 background check model. |
ce8b445 to
2cef504
Compare
|
DDvO
left a comment
There was a problem hiding this comment.
Nice first draft.
At appropriate time, some updates and improvements will be due.
| NonceRequest nonceRequest = new NonceRequest( | ||
| attestationContext.getNonceRequestLen(), | ||
| attestationContext.getNonceRequestType(), | ||
| attestationContext.getNonceRequestHint(), | ||
| attestationContext.getNonceRequestVendorextension()); | ||
| NonceRequestValue nonceRequestValue = new NonceRequestValue(new NonceRequest[] {nonceRequest}); |
There was a problem hiding this comment.
So here you generate a request for a single nonce.
Please add at least a TODO that this should be generalized to request for multiple nonces.
There was a problem hiding this comment.
Needs change of
ClientAttestationContext ClientContext:getAttestationContext()
replace with
Collection <ClientAttestationContext> ClientContext:getAttestationContext()
| final InfoTypeAndValue[] itav = content.toInfoTypeAndValueArray(); | ||
| if (itav != null) { | ||
| for (final InfoTypeAndValue aktitav : itav) { | ||
| if (AttestationObjectIdentifiers.id_it_NonceResponse.equals(aktitav.getInfoType())) { |
There was a problem hiding this comment.
Its about robustness -> Ignore, what you are unable to handle.
| final GenRepContent content = (GenRepContent) ratNonceResponseBody.getContent(); | ||
| final InfoTypeAndValue[] itav = content.toInfoTypeAndValueArray(); | ||
| if (itav != null) { | ||
| for (final InfoTypeAndValue aktitav : itav) { |
There was a problem hiding this comment.
Should throw an error if not getting exactly one ITAV
| return null; | ||
| } | ||
| final NonceResponseValue ratNonce = NonceResponseValue.getInstance(infoValue); | ||
| NonceResponse[] nonceResponses = ratNonce.getNonceResponse(); |
There was a problem hiding this comment.
Should check that the number of nonces obtains equals the number requested, which so far is always 1.
| EvidenceBundle evidenceBundle = EvidenceBundle.getInstance(evidenceItav.getParsedValue()); | ||
| EvidenceStatement[] evidences = evidenceBundle.getEvidences(); | ||
| AttestationResult[] attestationResults = new AttestationResult[evidences.length]; |
There was a problem hiding this comment.
I think the worst thing that could happen here is a OutOfMemoryError exception, right?
If so, at which level would it be caught and handled?
| * @param evidence evidence provided by EE as DER encoded {@link EvidenceStatement} | ||
| * @return verification result as DER encoded {@link AttestationResult} | ||
| */ | ||
| byte[] processRatVerification(byte[] transactionId, byte[] evidence); |
There was a problem hiding this comment.
I think the verifier should also get the certs from the evicence/attestation bundle.
| * AttestationResultBundle ::= SEQUENCE { | ||
| * results SEQUENCE SIZE (1..MAX) OF AttestationResult, | ||
| * certs SEQUENCE SIZE (1..MAX) OF CertificateChoices OPTIONAL, | ||
| * -- CertificateChoices MUST only contain certificate or other, | ||
| * -- see Section 10.2.2 of [RFC5652] |
There was a problem hiding this comment.
For some reason, this structure has disappeared in https://datatracker.ietf.org/doc/html/draft-ietf-lamps-csr-attestation-22
| } | ||
| final NonceResponseValue ratNonce = NonceResponseValue.getInstance(infoValue); | ||
| NonceResponse[] nonceResponses = ratNonce.getNonceResponse(); | ||
| EvidenceStatement[] evidenceStatements = new EvidenceStatement[nonceResponses.length]; |
There was a problem hiding this comment.
Does the number of evidence statements always follow the number of nonce responses?
Please add at least a respective TODO to generalize this.
| return null; | ||
| } | ||
| EvidenceBundle evidenceBundle = EvidenceBundle.getInstance(evidenceItav.getParsedValue()); | ||
| EvidenceStatement[] evidences = evidenceBundle.getEvidences(); |
There was a problem hiding this comment.
Should the number of evidence/attestation statements follow the number of nonce requests/responses?
Please add at least a respective TODO to possibly check for this.
| NonceRequest aktRequest = nonceRequests[i]; | ||
| NonceResponseRet ret = verifyAdapter.generateNonce( | ||
| msg.getHeader().getTransactionID().getOctets(), | ||
| ifNotNull(aktRequest.getLen(), ASN1Integer::getValue), |
There was a problem hiding this comment.
@ralienpp is right, an attacker could easily provoke an out-of-memory condition and thus do a DoS attack.
Clearly the size of the nonces should be limited to a sensible value.
| PKIMessage buildFurtherRequest( | ||
| final PKIMessage formerResponse, | ||
| final PKIBody requestBody, | ||
| final boolean withImplicitConfirm, | ||
| final int pvno) |
There was a problem hiding this comment.
Maybe it is simpler to keep at least part of these argument in some state fields and take them from there?
I suppose one could even avoid distinguishing between methods building initial vs. further requests.
There was a problem hiding this comment.
Holding (transaction) states global and non final makes it hard to implement concurrency and slows down the VM. So I would keep everything local and final as much as possible.
| * Siemens proprietary extension to carry additional data | ||
| * @return additional data or <code>null</code> | ||
| */ | ||
| default byte[] getNonceRequestVendorextension() { |
There was a problem hiding this comment.
Consider getNonceRequestVendorExtension (camelCase) instead of getNonceRequestVendorextension.
| @@ -409,6 +418,51 @@ private boolean grantsImplicitConfirm(final PKIMessage msg) { | |||
| public EnrollmentResult invokeEnrollment() { | |||
There was a problem hiding this comment.
This method is around 200 lines of code with a high complexity.
I recommend refactoring it into smaller methods to improve readability and simplify unit testing. Helps future maintenance.
| * Siemens proprietary extension to carry additional data | ||
| * @return additional data or <code>null</code> | ||
| */ | ||
| default byte[] getVendorextension() { |
There was a problem hiding this comment.
Recommended to rename getVendorextension to getVendorExtension
| BigInteger len, | ||
| String type, | ||
| String hint, | ||
| byte[] vendorextension, |



Description
Implement remote attestation message flow over CMP as far as specified and stable in