Commit 2b24d6ec authored by Josh Ji's avatar Josh Ji

implement the asking flow to IDP

parent 1d32e5f2
...@@ -57,6 +57,11 @@ ...@@ -57,6 +57,11 @@
<artifactId>webauthn4j-core</artifactId> <artifactId>webauthn4j-core</artifactId>
<version>0.20.5.RELEASE</version> <version>0.20.5.RELEASE</version>
</dependency> </dependency>
<dependency>
<groupId>co.nstant.in</groupId>
<artifactId>cbor</artifactId>
<version>0.8</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
......
package com.example.rpserver.controller; package com.example.rpserver.controller;
import co.nstant.in.cbor.CborDecoder;
import co.nstant.in.cbor.CborException;
import co.nstant.in.cbor.model.Array;
import co.nstant.in.cbor.model.ByteString;
import co.nstant.in.cbor.model.DataItem;
import co.nstant.in.cbor.model.UnicodeString;
import com.example.rpserver.model.Credential; import com.example.rpserver.model.Credential;
import com.example.rpserver.model.FidoUser; import com.example.rpserver.model.FidoUser;
import com.example.rpserver.model.Response; import com.example.rpserver.model.Response;
...@@ -18,13 +24,16 @@ import com.webauthn4j.validator.attestation.trustworthiness.self.NullSelfAttesta ...@@ -18,13 +24,16 @@ import com.webauthn4j.validator.attestation.trustworthiness.self.NullSelfAttesta
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.net.http.HttpResponse;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List;
@RestController @RestController
public class MakeCredential { public class MakeCredential {
...@@ -39,10 +48,14 @@ public class MakeCredential { ...@@ -39,10 +48,14 @@ public class MakeCredential {
@ResponseBody @ResponseBody
@PostMapping("/BeginMakeCredential") @PostMapping("/BeginMakeCredential")
public ResponseEntity<PublicKeyCredentialCreationOptions> beginMakeCredential(@RequestParam("username") String username, public ResponseEntity<PublicKeyCredentialCreationOptions> beginMakeCredential(
@RequestParam("advanced") String advanced, @RequestParam("conveyance") String conveyance,
@RequestParam("advancedOptions") String advancedOptions, @RequestParam("attachment") String attachment,
@RequestHeader(HttpHeaders.HOST) String host){ @RequestParam("username") String username)
{
byte[] userIdBytes = new byte[32]; byte[] userIdBytes = new byte[32];
secureRandom.nextBytes(userIdBytes); secureRandom.nextBytes(userIdBytes);
PublicKeyCredentialUserEntity userEntity = new PublicKeyCredentialUserEntity(userIdBytes, username, username); PublicKeyCredentialUserEntity userEntity = new PublicKeyCredentialUserEntity(userIdBytes, username, username);
...@@ -51,7 +64,22 @@ public class MakeCredential { ...@@ -51,7 +64,22 @@ public class MakeCredential {
LinkedList<PublicKeyCredentialParameters> parameters = new LinkedList<>(); LinkedList<PublicKeyCredentialParameters> parameters = new LinkedList<>();
parameters.add(new PublicKeyCredentialParameters(PublicKeyCredentialType.PUBLIC_KEY, COSEAlgorithmIdentifier.RS256)); parameters.add(new PublicKeyCredentialParameters(PublicKeyCredentialType.PUBLIC_KEY, COSEAlgorithmIdentifier.RS256));
parameters.add(new PublicKeyCredentialParameters(PublicKeyCredentialType.PUBLIC_KEY, COSEAlgorithmIdentifier.ES256)); parameters.add(new PublicKeyCredentialParameters(PublicKeyCredentialType.PUBLIC_KEY, COSEAlgorithmIdentifier.ES256));
PublicKeyCredentialCreationOptions options = new PublicKeyCredentialCreationOptions(rp, userEntity, challenge, parameters);
PublicKeyCredentialCreationOptions options = new PublicKeyCredentialCreationOptions(
rp,
userEntity,
challenge,
parameters,
null,
null,
new AuthenticatorSelectionCriteria(attachment.equals("cross-platform")?AuthenticatorAttachment.CROSS_PLATFORM:AuthenticatorAttachment.PLATFORM,null,null,null),
conveyance.equals("direct")?AttestationConveyancePreference.DIRECT:AttestationConveyancePreference.NONE,
null);
logger.debug("PublicKeyCredentialCreationOptions : {}", options);
FidoUser fidoUser = new FidoUser(userIdBytes, challenge.toString(), username); FidoUser fidoUser = new FidoUser(userIdBytes, challenge.toString(), username);
userRepository.save(fidoUser); userRepository.save(fidoUser);
...@@ -71,16 +99,21 @@ public class MakeCredential { ...@@ -71,16 +99,21 @@ public class MakeCredential {
rawId = Base64Util.decode(rawId); rawId = Base64Util.decode(rawId);
// logger // logger
logger.info("clientDataJson : {}", new String(clientDataJSONBytes)); logger.debug("clientDataJson : {}", new String(clientDataJSONBytes));
logger.info("attestationObject hex String : {}", HexUtil.encodeToString(attestationObjectBytes)); logger.debug("attestationObject hex String : {}", HexUtil.encodeToString(attestationObjectBytes));
logger.info("rawId hex String : {}", HexUtil.encodeToString(rawId)); logger.debug("rawId hex String : {}", HexUtil.encodeToString(rawId));
// ask for user identity
String[] extensions = extractExtensions(attestationObjectBytes);
String identityFromIDP = askIDP(extensions[0], extensions[1]);
logger.debug("identityFromIDP : {}", identityFromIDP);
RegistrationRequest registrationRequest = new RegistrationRequest(attestationObjectBytes, clientDataJSONBytes); RegistrationRequest registrationRequest = new RegistrationRequest(attestationObjectBytes, clientDataJSONBytes);
LinkedList<AttestationStatementValidator> attestationStatementValidators = new LinkedList<>(); LinkedList<AttestationStatementValidator> attestationStatementValidators = new LinkedList<>();
WebAuthnManager webAuthnManager = new WebAuthnManager(attestationStatementValidators, new NullCertPathTrustworthinessValidator(), new NullSelfAttestationTrustworthinessValidator()); WebAuthnManager webAuthnManager = new WebAuthnManager(attestationStatementValidators, new NullCertPathTrustworthinessValidator(), new NullSelfAttestationTrustworthinessValidator());
RegistrationData registrationData = webAuthnManager.parse(registrationRequest); RegistrationData registrationData = webAuthnManager.parse(registrationRequest);
logger.info("registrationData {}", registrationData); logger.debug("registrationData {}", registrationData);
FidoUser user = userRepository.findByChallenge(registrationData.getCollectedClientData().getChallenge().toString()); FidoUser user = userRepository.findByChallenge(registrationData.getCollectedClientData().getChallenge().toString());
...@@ -94,4 +127,45 @@ public class MakeCredential { ...@@ -94,4 +127,45 @@ public class MakeCredential {
return ResponseEntity.ok().body(new Response(true, "Successfully created credential")); return ResponseEntity.ok().body(new Response(true, "Successfully created credential"));
} }
private String[] extractExtensions(byte[] attestationObjectBytes){
String hmac = "";
String Cx = "";
try {
co.nstant.in.cbor.model.Map attestationObjectCbor = (co.nstant.in.cbor.model.Map) CborDecoder.decode(attestationObjectBytes).get(0);
for (DataItem key : attestationObjectCbor.getKeys())
logger.debug("first layer keys : {} : ", key);
co.nstant.in.cbor.model.Map attestationStatement = (co.nstant.in.cbor.model.Map) attestationObjectCbor.get(new UnicodeString("attStmt"));
for (DataItem key : attestationStatement.getKeys())
logger.debug("keys under attStmt node : {}", key);
List<DataItem> extensions = ((Array) attestationStatement.get(new UnicodeString("extensions"))).getDataItems();
for (DataItem item : extensions)
logger.debug("extensions : {}", item);
byte[][] extensionSendsOut = new byte[2][];
extensionSendsOut[0] = ((ByteString) extensions.get(0)).getBytes();
extensionSendsOut[1] = ((ByteString) extensions.get(1)).getBytes();
hmac = HexUtil.encodeToString(extensionSendsOut[0]); // param 1 : hmac
Cx = HexUtil.encodeToString(extensionSendsOut[1]); // param 2 : Cx
} catch (CborException e) {
e.printStackTrace();
}
return new String[]{hmac, Cx};
}
private String askIDP(String hmac, String Cx){
RestTemplate restTemplate = new RestTemplate();
String uri = "http://localhost:8086/api/idp/askIdentity";
HashMap<String, String> map = new HashMap<>();
String base64hmac = Base64Util.encodeToString(HexUtil.decode(hmac));
String base64Cx = Base64Util.encodeToString(HexUtil.decode(Cx));
map.put("HMAC", base64hmac);
map.put("Cx", base64Cx);
return restTemplate.postForObject(uri, map, String.class);
}
} }
...@@ -304,8 +304,9 @@ function makeCredential(advancedOptions) { ...@@ -304,8 +304,9 @@ function makeCredential(advancedOptions) {
let username = document.querySelector('#username').value; let username = document.querySelector('#username').value;
return _fetch('/BeginMakeCredential', { return _fetch('/BeginMakeCredential', {
advanced: true, // advancedOptions: JSON.stringify(advancedOptions),
advancedOptions: JSON.stringify(advancedOptions), conveyance: advancedOptions.attestationConveyancePreference,
attachment: advancedOptions.authenticatorAttachment,
// Tyler ----------------- // Tyler -----------------
username: username username: username
}) })
......
package com.example.rpserver; package com.example.rpserver;
import co.nstant.in.cbor.CborDecoder;
import co.nstant.in.cbor.CborException;
import co.nstant.in.cbor.model.Array;
import co.nstant.in.cbor.model.ByteString;
import co.nstant.in.cbor.model.DataItem;
import co.nstant.in.cbor.model.UnicodeString;
import com.webauthn4j.util.Base64Util;
import com.webauthn4j.util.HexUtil;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpEntity;
import org.springframework.web.client.RestTemplate;
import java.util.HashMap;
import java.util.List;
@SpringBootTest @SpringBootTest
class RpServerApplicationTests { class RpServerApplicationTests {
Logger logger = LoggerFactory.getLogger(RpServerApplicationTests.class);
@Test @Test
void contextLoads() { void contextLoads() throws CborException {
String hexString = "A363666D74667061636B65646761747453746D74A463616C67266373696758483046022100AAE24FC859C63F9443E1E0CEE91A70544B43BB4392FF10559462E75F75B4B5B0022100DD473DDA4DB18F1E17303FE8693A0AAF252A55ABAA1B14BD748F89769BED4A2663783563815901403082013C3081E4A003020102020A47901280001155957352300A06082A8648CE3D0403023017311530130603550403130C476E756262792050696C6F74301E170D3132303831343138323933325A170D3133303831343138323933325A3031312F302D0603550403132650696C6F74476E756262792D302E342E312D34373930313238303030313135353935373335323059301306072A8648CE3D020106082A8648CE3D030107034200048D617E65C9508E64BCC5673AC82A6799DA3C1446682C258C463FFFDF58DFD2FA3E6C378B53D795C4A4DFFB4199EDD7862F23ABAF0203B4B8911BA0569994E101300A06082A8648CE3D0403020347003044022060CDB6061E9C22262D1AAC1D96D8C70829B2366531DDA268832CB836BCD30DFA0220631B1459F09E6330055722C8D89B7F48883B9089B88D60D1D9795902B30410DF6A657874656E73696F6E738258201FA3CD730BC2E3630D22DB8C9B4A6A4B30C65FE269E023A995E18A2265BB508F504D3A97BCBBA5F38B0E4640C38F09B3F7686175746844617461589449960DE5880E8C687434170F6476605B8FE4AEB9A28632C7995CF3BA831D976345000000007465737461616775696470726C61625F0010C78C7AA8AE8EDB531B01C82C63B8EE3FA5010203262001215820B8A7649E3322C6B22F8E6F06D02CF93E48A27580ED64E19F4056BD92849122C9225820726B2E1FFB54D8BA5A790D398EED09478D62351FA8CC0AFACCA78B394A0D7B51";
// hmac=1FA3CD730BC2E3630D22DB8C9B4A6A4B30C65FE269E023A995E18A2265BB508F
// Cx=4D3A97BCBBA5F38B0E4640C38F09B3F7
byte[] hexBytes = HexUtil.decode(hexString);
co.nstant.in.cbor.model.Map attestationObjectCbor = (co.nstant.in.cbor.model.Map) CborDecoder.decode(hexBytes).get(0);
for (DataItem key : attestationObjectCbor.getKeys())
logger.info("first layer keys : {} : ", key);
co.nstant.in.cbor.model.Map attestationStatement = (co.nstant.in.cbor.model.Map) attestationObjectCbor.get(new UnicodeString("attStmt"));
for (DataItem key : attestationStatement.getKeys())
logger.info("keys under attStmt node : {}", key);
List<DataItem> extensions = ((Array) attestationStatement.get(new UnicodeString("extensions"))).getDataItems();
for (DataItem item : extensions)
logger.info("extensions : {}", item);
byte[][] extensionSendsOut = new byte[2][];
extensionSendsOut[0] = ((ByteString) extensions.get(0)).getBytes();
extensionSendsOut[1] = ((ByteString) extensions.get(1)).getBytes();
String hmac = HexUtil.encodeToString(extensionSendsOut[0]); // param 1 : hmac
String Cx = HexUtil.encodeToString(extensionSendsOut[1]); // param 2 : Cx
logger.info("p1 : {}", hmac);
logger.info("p2 : {}", Cx);
logger.info("result from IDP : {}", askIDP(hmac, Cx));
}
private String askIDP(String hmac, String Cx){
RestTemplate restTemplate = new RestTemplate();
String uri = "http://localhost:8086/api/idp/askIdentity";
HashMap<String, String> map = new HashMap<>();
String base64hmac = Base64Util.encodeToString(HexUtil.decode(hmac));
String base64Cx = Base64Util.encodeToString(HexUtil.decode(Cx));
map.put("HMAC", base64hmac);
map.put("Cx", base64Cx);
return restTemplate.postForObject(uri, map, String.class);
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment