use of com.yubico.webauthn.data.ByteArray in project java-webauthn-server by Yubico.
the class WebAuthnServer method startRegistration.
public Either<String, RegistrationRequest> startRegistration(@NonNull String username, @NonNull String displayName, Optional<String> credentialNickname, ResidentKeyRequirement residentKeyRequirement, Optional<ByteArray> sessionToken) throws ExecutionException {
logger.trace("startRegistration username: {}, credentialNickname: {}", username, credentialNickname);
final Collection<CredentialRegistration> registrations = userStorage.getRegistrationsByUsername(username);
final Optional<UserIdentity> existingUser = registrations.stream().findAny().map(CredentialRegistration::getUserIdentity);
final boolean permissionGranted = existingUser.map(userIdentity -> sessions.isSessionForUser(userIdentity.getId(), sessionToken)).orElse(true);
if (permissionGranted) {
final UserIdentity registrationUserId = existingUser.orElseGet(() -> UserIdentity.builder().name(username).displayName(displayName).id(generateRandom(32)).build());
RegistrationRequest request = new RegistrationRequest(username, credentialNickname, generateRandom(32), rp.startRegistration(StartRegistrationOptions.builder().user(registrationUserId).authenticatorSelection(AuthenticatorSelectionCriteria.builder().residentKey(residentKeyRequirement).build()).build()), Optional.of(sessions.createSession(registrationUserId.getId())));
registerRequestStorage.put(request.getRequestId(), request);
return Either.right(request);
} else {
return Either.left("The username \"" + username + "\" is already registered.");
}
}
use of com.yubico.webauthn.data.ByteArray in project java-webauthn-server by Yubico.
the class WebAuthnServer method deregisterCredential.
public Either<List<String>, DeregisterCredentialResult> deregisterCredential(@NonNull ByteArray sessionToken, ByteArray credentialId) {
logger.trace("deregisterCredential session: {}, credentialId: {}", sessionToken, credentialId);
if (credentialId == null || credentialId.getBytes().length == 0) {
return Either.left(Collections.singletonList("Credential ID must not be empty."));
}
Optional<ByteArray> session = sessions.getSession(sessionToken);
if (session.isPresent()) {
ByteArray userHandle = session.get();
Optional<String> username = userStorage.getUsernameForUserHandle(userHandle);
if (username.isPresent()) {
Optional<CredentialRegistration> credReg = userStorage.getRegistrationByUsernameAndCredentialId(username.get(), credentialId);
if (credReg.isPresent()) {
userStorage.removeRegistrationByUsername(username.get(), credReg.get());
return Either.right(new DeregisterCredentialResult(credReg.get(), !userStorage.userExists(username.get())));
} else {
return Either.left(Collections.singletonList("Credential ID not registered:" + credentialId));
}
} else {
return Either.left(Collections.singletonList("Invalid user handle"));
}
} else {
return Either.left(Collections.singletonList("Invalid session"));
}
}
use of com.yubico.webauthn.data.ByteArray in project java-webauthn-server by Yubico.
the class FidoMetadataDownloader method retrieveBlob.
/**
* @throws Base64UrlException if the metadata BLOB is not a well-formed JWT in compact
* serialization.
* @throws CertPathValidatorException if the downloaded or explicitly configured BLOB fails
* certificate path validation.
* @throws CertificateException if the BLOB signing certificate chain fails to parse.
* @throws IOException if any of the following fails: downloading the BLOB, reading or writing the
* cache file (if any), or parsing the BLOB contents.
* @throws InvalidAlgorithmParameterException if certificate path validation fails.
* @throws InvalidKeyException if signature verification fails.
* @throws UnexpectedLegalHeader if the downloaded BLOB (if any) contains a <code>"legalHeader"
* </code> value not configured in {@link
* FidoMetadataDownloaderBuilder.Step1#expectLegalHeader(String...)
* expectLegalHeader(String...)} but is otherwise valid. The downloaded BLOB will not be
* written to cache in this case.
* @throws NoSuchAlgorithmException if signature verification fails.
* @throws SignatureException if signature verification fails.
* @throws FidoMetadataDownloaderException if the explicitly configured BLOB (if any) has a bad
* signature.
*/
private MetadataBLOB retrieveBlob(X509Certificate trustRootCertificate) throws Base64UrlException, CertPathValidatorException, CertificateException, IOException, InvalidAlgorithmParameterException, InvalidKeyException, UnexpectedLegalHeader, NoSuchAlgorithmException, SignatureException, FidoMetadataDownloaderException {
if (blobJwt != null) {
return parseAndVerifyBlob(new ByteArray(blobJwt.getBytes(StandardCharsets.UTF_8)), trustRootCertificate);
} else {
final Optional<ByteArray> cachedContents;
if (blobCacheFile != null) {
cachedContents = readCacheFile(blobCacheFile);
} else {
cachedContents = blobCacheSupplier.get();
}
final MetadataBLOB cachedBlob = cachedContents.map(cached -> {
try {
return parseAndVerifyBlob(cached, trustRootCertificate);
} catch (Exception e) {
return null;
}
}).orElse(null);
if (cachedBlob != null && cachedBlob.getPayload().getNextUpdate().atStartOfDay().atZone(clock.getZone()).isAfter(clock.instant().atZone(clock.getZone()))) {
return cachedBlob;
} else {
final ByteArray downloaded = download(blobUrl);
try {
final MetadataBLOB downloadedBlob = parseAndVerifyBlob(downloaded, trustRootCertificate);
if (cachedBlob == null || downloadedBlob.getPayload().getNo() > cachedBlob.getPayload().getNo()) {
if (expectedLegalHeaders.contains(downloadedBlob.getPayload().getLegalHeader())) {
if (blobCacheFile != null) {
new FileOutputStream(blobCacheFile).write(downloaded.getBytes());
}
if (blobCacheConsumer != null) {
blobCacheConsumer.accept(downloaded);
}
return downloadedBlob;
} else {
throw new UnexpectedLegalHeader(cachedBlob, downloadedBlob);
}
} else {
return cachedBlob;
}
} catch (FidoMetadataDownloaderException e) {
if (e.getReason() == FidoMetadataDownloaderException.Reason.BAD_SIGNATURE && cachedBlob != null) {
return cachedBlob;
} else {
throw e;
}
}
}
}
}
use of com.yubico.webauthn.data.ByteArray in project java-webauthn-server by Yubico.
the class FidoMetadataDownloader method retrieveTrustRootCert.
/**
* @throws CertificateException if the trust root certificate was downloaded and passed the
* SHA-256 integrity check, but does not contain a currently valid X.509 DER certificate.
* @throws DigestException if the trust root certificate was downloaded but failed the SHA-256
* integrity check.
* @throws IOException if the trust root certificate download failed, or if reading or writing the
* cache file (if any) failed.
* @throws NoSuchAlgorithmException if the SHA-256 algorithm is not available.
*/
private X509Certificate retrieveTrustRootCert() throws CertificateException, DigestException, IOException, NoSuchAlgorithmException {
if (trustRootCertificate != null) {
return trustRootCertificate;
} else {
final Optional<ByteArray> cachedContents;
if (trustRootCacheFile != null) {
cachedContents = readCacheFile(trustRootCacheFile);
} else {
cachedContents = trustRootCacheSupplier.get();
}
X509Certificate cert = null;
if (cachedContents.isPresent()) {
try {
final X509Certificate cachedCert = CertificateParser.parseDer(cachedContents.get().getBytes());
cachedCert.checkValidity(Date.from(clock.instant()));
cert = cachedCert;
} catch (CertificateException e) {
// Fall through
}
}
if (cert == null) {
final ByteArray downloaded = verifyHash(download(trustRootUrl), trustRootSha256);
if (downloaded == null) {
throw new DigestException("Downloaded trust root certificate matches none of the acceptable hashes.");
}
cert = CertificateParser.parseDer(downloaded.getBytes());
cert.checkValidity(Date.from(clock.instant()));
if (trustRootCacheFile != null) {
new FileOutputStream(trustRootCacheFile).write(downloaded.getBytes());
}
if (trustRootCacheConsumer != null) {
trustRootCacheConsumer.accept(downloaded);
}
}
return cert;
}
}
use of com.yubico.webauthn.data.ByteArray in project java-webauthn-server by Yubico.
the class FidoU2fAttestationStatementVerifier method getRawUserPublicKey.
private static ByteArray getRawUserPublicKey(AttestationObject attestationObject) throws IOException, CoseException {
final ByteArray pubkeyCose = attestationObject.getAuthenticatorData().getAttestedCredentialData().get().getCredentialPublicKey();
final PublicKey pubkey;
try {
pubkey = WebAuthnCodecs.importCosePublicKey(pubkeyCose);
} catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
throw ExceptionUtil.wrapAndLog(log, "Failed to decode public key: " + pubkeyCose.getHex(), e);
}
final ECPublicKey ecPubkey;
try {
ecPubkey = (ECPublicKey) pubkey;
} catch (ClassCastException e) {
throw new RuntimeException("U2F supports only EC keys, was: " + pubkey);
}
return WebAuthnCodecs.ecPublicKeyToRaw(ecPubkey);
}
Aggregations