/** * Return the crypto context resulting from key response data contained in the provided header. * * <p>The {@link MslException}s thrown by this method will not have the entity or user set. * * @param ctx MSL context. * @param header header. * @param keyRequestData key request data for key exchange. * @return the crypto context or null if the header does not contain key response data or is for * an error message. * @throws MslKeyExchangeException if there is an error with the key request data or key response * data or the key exchange scheme is not supported. * @throws MslCryptoException if the crypto context cannot be created. * @throws MslEncodingException if there is an error parsing the JSON. * @throws MslMasterTokenException if the master token is not trusted and needs to be. * @throws MslEntityAuthException if there is a problem with the master token identity. */ private static ICryptoContext getKeyxCryptoContext( final MslContext ctx, final MessageHeader header, final Set<KeyRequestData> keyRequestData) throws MslCryptoException, MslKeyExchangeException, MslEncodingException, MslMasterTokenException, MslEntityAuthException { // Pull the header data. final MessageHeader messageHeader = (MessageHeader) header; final MasterToken masterToken = messageHeader.getMasterToken(); final KeyResponseData keyResponse = messageHeader.getKeyResponseData(); // If there is no key response data then return null. if (keyResponse == null) return null; // If the key response data master token is decrypted then use the // master token keys to create the crypto context. final MasterToken keyxMasterToken = keyResponse.getMasterToken(); if (keyxMasterToken.isDecrypted()) return new SessionCryptoContext(ctx, keyxMasterToken); // Perform the key exchange. final KeyExchangeScheme responseScheme = keyResponse.getKeyExchangeScheme(); final KeyExchangeFactory factory = ctx.getKeyExchangeFactory(responseScheme); if (factory == null) throw new MslKeyExchangeException(MslError.KEYX_FACTORY_NOT_FOUND, responseScheme.name()); // Attempt the key exchange but if it fails then try with the next // key request data before giving up. MslException keyxException = null; final Iterator<KeyRequestData> keyRequests = keyRequestData.iterator(); while (keyRequests.hasNext()) { final KeyRequestData keyRequest = keyRequests.next(); final KeyExchangeScheme requestScheme = keyRequest.getKeyExchangeScheme(); // Skip incompatible key request data. if (!responseScheme.equals(requestScheme)) continue; try { return factory.getCryptoContext(ctx, keyRequest, keyResponse, masterToken); } catch (final MslKeyExchangeException e) { if (!keyRequests.hasNext()) throw e; keyxException = e; } catch (final MslEncodingException e) { if (!keyRequests.hasNext()) throw e; keyxException = e; } catch (final MslMasterTokenException e) { if (!keyRequests.hasNext()) throw e; keyxException = e; } catch (final MslEntityAuthException e) { if (!keyRequests.hasNext()) throw e; keyxException = e; } } // We did not perform a successful key exchange. If we caught an // exception then throw that exception now. if (keyxException != null) { if (keyxException instanceof MslKeyExchangeException) throw (MslKeyExchangeException) keyxException; if (keyxException instanceof MslEncodingException) throw (MslEncodingException) keyxException; if (keyxException instanceof MslMasterTokenException) throw (MslMasterTokenException) keyxException; if (keyxException instanceof MslEntityAuthException) throw (MslEntityAuthException) keyxException; throw new MslInternalException( "Unexpected exception caught during key exchange.", keyxException); } // If we did not perform a successful key exchange then the // payloads will not decrypt properly. Throw an exception. throw new MslKeyExchangeException( MslError.KEYX_RESPONSE_REQUEST_MISMATCH, Arrays.toString(keyRequestData.toArray())); }