Search in sources :

Example 1 with ByteIterator

use of org.wildfly.common.iteration.ByteIterator in project wildfly-elytron by wildfly-security.

the class OAuth2Server method parseInitialClientMessage.

public OAuth2InitialClientMessage parseInitialClientMessage(byte[] fromBytes) throws AuthenticationMechanismException {
    byte[] messageBytes = fromBytes.clone();
    ByteIterator byteIterator = ByteIterator.ofBytes(fromBytes.clone());
    try {
        final char cbindFlag = (char) byteIterator.next();
        if (cbindFlag != 'n') {
            throw log.mechChannelBindingNotSupported();
        }
        String authorizationID = null;
        if (byteIterator.next() == ',') {
            final int c = byteIterator.next();
            if (c == 'a') {
                if (byteIterator.next() != '=') {
                    throw log.mechInvalidClientMessage();
                }
                authorizationID = byteIterator.delimitedBy(',').asUtf8String().drainToString();
                if (byteIterator.next() != ',') {
                    throw ElytronMessages.log.mechInvalidClientMessage();
                }
            }
        }
        String auth = getValue("auth", byteIterator.asUtf8String().drainToString());
        if (auth == null) {
            throw log.mechInvalidClientMessage();
        }
        return new OAuth2InitialClientMessage(authorizationID, auth, messageBytes);
    } catch (NoSuchElementException ignored) {
        throw ElytronMessages.log.mechInvalidMessageReceived();
    }
}
Also used : ByteIterator(org.wildfly.common.iteration.ByteIterator) NoSuchElementException(java.util.NoSuchElementException)

Example 2 with ByteIterator

use of org.wildfly.common.iteration.ByteIterator in project wildfly-elytron by wildfly-security.

the class ScramClient method parseInitialServerMessage.

public ScramInitialServerMessage parseInitialServerMessage(final ScramInitialClientMessage initialResponse, final byte[] bytes) throws AuthenticationMechanismException {
    final byte[] challenge = bytes.clone();
    final ByteIterator bi = ByteIterator.ofBytes(challenge);
    final byte[] serverNonce;
    final byte[] salt;
    final int iterationCount;
    try {
        if (bi.peekNext() == 'e') {
            bi.next();
            if (bi.next() == '=') {
                throw saslScram.scramServerRejectedAuthentication(ScramServerErrorCode.fromErrorString(bi.delimitedBy(',').asUtf8String().drainToString()));
            }
            throw saslScram.mechInvalidMessageReceived();
        }
        if (bi.next() != 'r' || bi.next() != '=') {
            throw saslScram.mechInvalidMessageReceived();
        }
        final byte[] clientNonce = initialResponse.getRawNonce();
        if (!bi.limitedTo(clientNonce.length).contentEquals(ByteIterator.ofBytes(clientNonce))) {
            throw saslScram.mechNoncesDoNotMatch();
        }
        serverNonce = bi.delimitedBy(',').drain();
        // it's a ,
        bi.next();
        if (bi.next() != 's' || bi.next() != '=') {
            throw saslScram.mechInvalidMessageReceived();
        }
        salt = bi.delimitedBy(',').asUtf8String().base64Decode().drain();
        // it's a ,
        bi.next();
        if (bi.next() != 'i' || bi.next() != '=') {
            throw saslScram.mechInvalidMessageReceived();
        }
        iterationCount = ScramUtil.parsePosInt(bi);
        if (iterationCount < minimumIterationCount) {
            throw saslScram.mechIterationCountIsTooLow(iterationCount, minimumIterationCount);
        }
        if (iterationCount > maximumIterationCount) {
            throw saslScram.mechIterationCountIsTooHigh(iterationCount, maximumIterationCount);
        }
    } catch (NoSuchElementException | DecodeException | NumberFormatException ex) {
        throw saslScram.mechInvalidMessageReceived();
    }
    return new ScramInitialServerMessage(initialResponse, serverNonce, salt, iterationCount, challenge);
}
Also used : ByteIterator(org.wildfly.common.iteration.ByteIterator) DecodeException(org.wildfly.common.codec.DecodeException) NoSuchElementException(java.util.NoSuchElementException)

Example 3 with ByteIterator

use of org.wildfly.common.iteration.ByteIterator in project wildfly-elytron by wildfly-security.

the class ScramServer method parseInitialClientMessage.

/**
 * Construct an initial response object from a byte array.
 *
 * @param bindingCallback the optional channel binding callback result (may be {@code null})
 * @param bytes the message bytes (must not be {@code null})
 * @return the constructed initial response (not {@code null})
 * @throws AuthenticationMechanismException if the content of the message is invalid
 */
public ScramInitialClientMessage parseInitialClientMessage(ChannelBindingCallback bindingCallback, byte[] bytes) throws AuthenticationMechanismException {
    byte[] response = bytes.clone();
    ByteIterator bi = ByteIterator.ofBytes(response);
    try {
        final char cbindFlag = (char) bi.next();
        final boolean binding;
        final String bindingType;
        final byte[] bindingData;
        if (bindingCallback != null) {
            bindingType = bindingCallback.getBindingType();
            bindingData = bindingCallback.getBindingData();
        } else {
            bindingType = null;
            bindingData = null;
        }
        if (cbindFlag == 'p') {
            if (!mechanism.isPlus()) {
                throw new ScramServerException(saslScram.mechChannelBindingNotSupported(), ScramServerErrorCode.SERVER_DOES_NOT_SUPPORT_CHANNEL_BINDING);
            }
            if (bindingType == null || bindingData == null) {
                throw new ScramServerException(saslScram.mechChannelBindingNotProvided(), ScramServerErrorCode.CHANNEL_BINDING_NOT_PROVIDED);
            }
            if (bi.next() != '=') {
                throw saslScram.mechInvalidMessageReceived();
            }
            if (!bindingType.equals(bi.delimitedBy(',').asUtf8String().drainToString())) {
                throw new ScramServerException(saslScram.mechChannelBindingTypeMismatch(), ScramServerErrorCode.UNSUPPORTED_CHANNEL_BINDING_TYPE);
            }
            binding = true;
        } else if (cbindFlag == 'y') {
            if (mechanism.isPlus()) {
                throw new ScramServerException(saslScram.mechChannelBindingNotProvided(), ScramServerErrorCode.SERVER_DOES_SUPPORT_CHANNEL_BINDING);
            }
            if (bindingType != null || bindingData != null) {
                throw new ScramServerException(saslScram.mechChannelBindingNotProvided(), ScramServerErrorCode.SERVER_DOES_SUPPORT_CHANNEL_BINDING);
            }
            binding = true;
        } else if (cbindFlag == 'n') {
            if (mechanism.isPlus()) {
                throw new ScramServerException(saslScram.mechChannelBindingNotProvided(), ScramServerErrorCode.SERVER_DOES_SUPPORT_CHANNEL_BINDING);
            }
            if (bindingType != null || bindingData != null) {
                throw new ScramServerException(saslScram.mechChannelBindingNotProvided(), ScramServerErrorCode.SERVER_DOES_SUPPORT_CHANNEL_BINDING);
            }
            binding = false;
        } else {
            throw saslScram.mechInvalidMessageReceived();
        }
        if (bi.next() != ',') {
            throw saslScram.mechInvalidMessageReceived();
        }
        // authorization ID
        final int c = bi.next();
        final String authorizationID;
        if (c == 'a') {
            if (bi.next() != '=') {
                throw saslScram.mechInvalidClientMessage();
            }
            authorizationID = bi.delimitedBy(',').asUtf8String().drainToString();
            // skip delimiter
            bi.next();
        } else if (c == ',') {
            authorizationID = null;
        } else {
            throw saslScram.mechInvalidClientMessage();
        }
        final int initialPartIndex = (int) bi.getIndex();
        // user name
        final String authenticationName;
        if (bi.next() == 'n') {
            if (bi.next() != '=') {
                throw saslScram.mechInvalidClientMessage();
            }
            ByteStringBuilder bsb = new ByteStringBuilder();
            StringPrep.encode(bi.delimitedBy(',').asUtf8String().drainToString(), bsb, StringPrep.PROFILE_SASL_QUERY | StringPrep.UNMAP_SCRAM_LOGIN_CHARS);
            authenticationName = new String(bsb.toArray(), StandardCharsets.UTF_8);
            // skip delimiter
            bi.next();
        } else {
            throw saslScram.mechInvalidClientMessage();
        }
        // random nonce
        if (bi.next() != 'r' || bi.next() != '=') {
            throw saslScram.mechInvalidClientMessage();
        }
        final byte[] nonce = bi.delimitedBy(',').drain();
        if (bi.hasNext()) {
            throw saslScram.mechInvalidClientMessage();
        }
        return new ScramInitialClientMessage(mechanism, authorizationID, authenticationName, binding, bindingType, bindingData, nonce, initialPartIndex, response);
    } catch (NoSuchElementException ignored) {
        throw saslScram.mechInvalidMessageReceived();
    }
}
Also used : ByteIterator(org.wildfly.common.iteration.ByteIterator) ScramServerException(org.wildfly.security.mechanism.ScramServerException) ByteStringBuilder(org.wildfly.common.bytes.ByteStringBuilder) NoSuchElementException(java.util.NoSuchElementException)

Example 4 with ByteIterator

use of org.wildfly.common.iteration.ByteIterator in project wildfly-elytron by wildfly-security.

the class NonceManager method useNonce.

/**
 * Attempt to use the supplied nonce.
 *
 * A nonce might not be usable for a couple of different reasons: -
 *
 * <ul>
 *     <li>It was created too far in the past.
 *     <li>Validation of the signature fails.
 *     <li>The nonce has been used previously and re-use is disabled.
 * </ul>
 *
 * @param nonce the nonce supplied by the client.
 * @param salt additional data to use when creating the overall signature for the nonce.
 * @return {@code true} if the nonce can be used, {@code false} otherwise.
 * @throws AuthenticationMechanismException
 */
boolean useNonce(final String nonce, byte[] salt, int nonceCount) throws AuthenticationMechanismException {
    try {
        MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
        ByteIterator byteIterator = CodePointIterator.ofChars(nonce.toCharArray()).base64Decode();
        byte[] nonceBytes = byteIterator.drain();
        if (nonceBytes.length != PREFIX_LENGTH + messageDigest.getDigestLength()) {
            throw log.invalidNonceLength();
        }
        byte[] nonceBytesWithoutPrefix = Arrays.copyOfRange(nonceBytes, PREFIX_LENGTH, nonceBytes.length);
        byte[] expectedNonce = digest(nonceBytes, 0, PREFIX_LENGTH, salt, messageDigest);
        if (MessageDigest.isEqual(nonceBytesWithoutPrefix, expectedNonce) == false) {
            if (log.isTraceEnabled()) {
                String saltString = salt == null ? "null" : ByteIterator.ofBytes(salt).hexEncode().drainToString();
                log.tracef("Nonce %s rejected due to failed comparison using secret key with seed %s.", nonce, saltString);
            }
            return false;
        }
        long age = System.nanoTime() - ByteBuffer.wrap(nonceBytes, Integer.BYTES, Long.BYTES).getLong();
        if (nonceCount > 0) {
            synchronized (usedNonces) {
                NonceState nonceState = usedNonces.get(nonce);
                if (nonceState != null && nonceState.highestNonceCount < 0) {
                    log.tracef("Nonce %s rejected due to previously being used without a nonce count", nonce);
                    return false;
                } else if (nonceState != null) {
                    if (nonceCount > nonceState.highestNonceCount) {
                        if (nonceState.futureCleanup.cancel(true)) {
                            nonceState.highestNonceCount = nonceCount;
                        } else {
                            log.tracef("Nonce %s rejected as unable to cancel clean up, likely at expiration time", nonce);
                            return false;
                        }
                    } else {
                        log.tracef("Nonce %s rejected due to highest seen nonce count %d being equal to or higher than the nonce count received %d", nonce, nonceState.highestNonceCount, nonceCount);
                        return false;
                    }
                } else {
                    if (age < 0 || age > validityPeriodNano) {
                        log.tracef("Nonce %s rejected due to age %d (ns) being less than 0 or greater than the validity period %d (ns)", nonce, age, validityPeriodNano);
                        return false;
                    }
                    nonceState = new NonceState();
                    nonceState.highestNonceCount = nonceCount;
                    usedNonces.put(nonce, nonceState);
                    if (log.isTraceEnabled()) {
                        log.tracef("Currently %d nonces being tracked", usedNonces.size());
                    }
                }
                nonceState.futureCleanup = executor.schedule(() -> {
                    synchronized (usedNonces) {
                        usedNonces.remove(nonce);
                    }
                }, nonceSessionTime, TimeUnit.MILLISECONDS);
            }
        } else {
            if (age < 0 || age > validityPeriodNano) {
                log.tracef("Nonce %s rejected due to age %d (ns) being less than 0 or greater than the validity period %d (ns)", nonce, age, validityPeriodNano);
                return false;
            }
            if (singleUse) {
                synchronized (usedNonces) {
                    NonceState nonceState = usedNonces.get(nonce);
                    if (nonceState != null) {
                        log.tracef("Nonce %s rejected due to previously being used", nonce);
                        return false;
                    } else {
                        nonceState = new NonceState();
                        usedNonces.put(nonce, nonceState);
                        if (log.isTraceEnabled()) {
                            log.tracef("Currently %d nonces being tracked", usedNonces.size());
                        }
                        executor.schedule(() -> {
                            synchronized (usedNonces) {
                                usedNonces.remove(nonce);
                            }
                        }, validityPeriodNano - age, TimeUnit.NANOSECONDS);
                    }
                }
            }
        }
        return true;
    } catch (GeneralSecurityException e) {
        throw new IllegalStateException(e);
    }
}
Also used : ByteIterator(org.wildfly.common.iteration.ByteIterator) GeneralSecurityException(java.security.GeneralSecurityException) MessageDigest(java.security.MessageDigest)

Example 5 with ByteIterator

use of org.wildfly.common.iteration.ByteIterator in project wildfly-elytron by wildfly-security.

the class BasicPasswordSpecEncoding method decode.

/**
 * Decode the given byte array and create a {@link PasswordSpec} from it.
 *
 * @param encoded the byte array representing the encoded password
 * @return a {@link PasswordSpec} instance created from the encoded password or null if no decoder was capable to decode the given format.
 */
public static PasswordSpec decode(byte[] encoded) {
    ByteIterator iterator = ByteIterator.ofBytes(encoded);
    int identifier;
    try {
        identifier = iterator.next();
    } catch (Exception e) {
        throw ElytronMessages.log.couldNotObtainKeySpecEncodingIdentifier();
    }
    switch(identifier) {
        case CLEAR_PASSWORD_SPEC_ID:
            return decodeClearPasswordSpec(iterator);
        case DIGEST_PASSWORD_SPEC_ID:
            return decodeDigestPasswordSpec(iterator);
        case HASH_PASSWORD_SPEC_ID:
            return decodeHashPasswordSpec(iterator);
        case SALTED_HASH_PASSWORD_SPEC_ID:
            return decodeSaltedHashPasswordSpec(iterator);
        case ITERATED_SALTED_HASH_SPEC_ID:
            return decodeIteratedSaltedHashPasswordSpec(iterator);
        default:
            return null;
    }
}
Also used : ByteIterator(org.wildfly.common.iteration.ByteIterator) InvalidKeySpecException(java.security.spec.InvalidKeySpecException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException)

Aggregations

ByteIterator (org.wildfly.common.iteration.ByteIterator)11 NoSuchElementException (java.util.NoSuchElementException)4 DecodeException (org.wildfly.common.codec.DecodeException)3 ScramServerException (org.wildfly.security.mechanism.ScramServerException)2 GeneralSecurityException (java.security.GeneralSecurityException)1 MessageDigest (java.security.MessageDigest)1 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)1 AlgorithmParameterSpec (java.security.spec.AlgorithmParameterSpec)1 InvalidKeySpecException (java.security.spec.InvalidKeySpecException)1 Matcher (java.util.regex.Matcher)1 Cipher (javax.crypto.Cipher)1 IvParameterSpec (javax.crypto.spec.IvParameterSpec)1 SecretKeySpec (javax.crypto.spec.SecretKeySpec)1 ByteStringBuilder (org.wildfly.common.bytes.ByteStringBuilder)1 CodePointIterator (org.wildfly.common.iteration.CodePointIterator)1