use of org.apache.hadoop.crypto.CipherOption in project hadoop by apache.
the class SaslDataTransferServer method doSaslHandshake.
/**
* This method actually executes the server-side SASL handshake.
*
* @param peer connection peer
* @param underlyingOut connection output stream
* @param underlyingIn connection input stream
* @param saslProps properties of SASL negotiation
* @param callbackHandler for responding to SASL callbacks
* @return new pair of streams, wrapped after SASL negotiation
* @throws IOException for any error
*/
private IOStreamPair doSaslHandshake(Peer peer, OutputStream underlyingOut, InputStream underlyingIn, Map<String, String> saslProps, CallbackHandler callbackHandler) throws IOException {
DataInputStream in = new DataInputStream(underlyingIn);
DataOutputStream out = new DataOutputStream(underlyingOut);
SaslParticipant sasl = SaslParticipant.createServerSaslParticipant(saslProps, callbackHandler);
int magicNumber = in.readInt();
if (magicNumber != SASL_TRANSFER_MAGIC_NUMBER) {
throw new InvalidMagicNumberException(magicNumber, dnConf.getEncryptDataTransfer());
}
try {
// step 1
byte[] remoteResponse = readSaslMessage(in);
byte[] localResponse = sasl.evaluateChallengeOrResponse(remoteResponse);
sendSaslMessage(out, localResponse);
// step 2 (server-side only)
List<CipherOption> cipherOptions = Lists.newArrayList();
remoteResponse = readSaslMessageAndNegotiationCipherOptions(in, cipherOptions);
localResponse = sasl.evaluateChallengeOrResponse(remoteResponse);
// SASL handshake is complete
checkSaslComplete(sasl, saslProps);
CipherOption cipherOption = null;
if (sasl.isNegotiatedQopPrivacy()) {
// Negotiate a cipher option
Configuration conf = dnConf.getConf();
cipherOption = negotiateCipherOption(conf, cipherOptions);
if (LOG.isDebugEnabled()) {
if (cipherOption == null) {
// No cipher suite is negotiated
String cipherSuites = conf.get(DFS_ENCRYPT_DATA_TRANSFER_CIPHER_SUITES_KEY);
if (cipherSuites != null && !cipherSuites.isEmpty()) {
// the server accepts some cipher suites, but the client does not.
LOG.debug("Server accepts cipher suites {}, " + "but client {} does not accept any of them", cipherSuites, peer.getRemoteAddressString());
}
} else {
LOG.debug("Server using cipher suite {} with client {}", cipherOption.getCipherSuite().getName(), peer.getRemoteAddressString());
}
}
}
// If negotiated cipher option is not null, wrap it before sending.
sendSaslMessageAndNegotiatedCipherOption(out, localResponse, wrap(cipherOption, sasl));
// stream pair.
return cipherOption != null ? createStreamPair(dnConf.getConf(), cipherOption, underlyingOut, underlyingIn, true) : sasl.createStreamPair(out, in);
} catch (IOException ioe) {
if (ioe instanceof SaslException && ioe.getCause() != null && ioe.getCause() instanceof InvalidEncryptionKeyException) {
// This could just be because the client is long-lived and hasn't gotten
// a new encryption key from the NN in a while. Upon receiving this
// error, the client will get a new encryption key from the NN and retry
// connecting to this DN.
sendInvalidKeySaslErrorMessage(out, ioe.getCause().getMessage());
} else {
sendGenericSaslErrorMessage(out, ioe.getMessage());
}
throw ioe;
}
}
use of org.apache.hadoop.crypto.CipherOption in project hadoop by apache.
the class DataTransferSaslUtil method negotiateCipherOption.
/**
* Negotiate a cipher option which server supports.
*
* @param conf the configuration
* @param options the cipher options which client supports
* @return CipherOption negotiated cipher option
*/
public static CipherOption negotiateCipherOption(Configuration conf, List<CipherOption> options) throws IOException {
// Negotiate cipher suites if configured. Currently, the only supported
// cipher suite is AES/CTR/NoPadding, but the protocol allows multiple
// values for future expansion.
String cipherSuites = conf.get(DFS_ENCRYPT_DATA_TRANSFER_CIPHER_SUITES_KEY);
if (cipherSuites == null || cipherSuites.isEmpty()) {
return null;
}
if (!cipherSuites.equals(CipherSuite.AES_CTR_NOPADDING.getName())) {
throw new IOException(String.format("Invalid cipher suite, %s=%s", DFS_ENCRYPT_DATA_TRANSFER_CIPHER_SUITES_KEY, cipherSuites));
}
if (options != null) {
for (CipherOption option : options) {
CipherSuite suite = option.getCipherSuite();
if (suite == CipherSuite.AES_CTR_NOPADDING) {
int keyLen = conf.getInt(DFS_ENCRYPT_DATA_TRANSFER_CIPHER_KEY_BITLENGTH_KEY, DFS_ENCRYPT_DATA_TRANSFER_CIPHER_KEY_BITLENGTH_DEFAULT) / 8;
CryptoCodec codec = CryptoCodec.getInstance(conf, suite);
byte[] inKey = new byte[keyLen];
byte[] inIv = new byte[suite.getAlgorithmBlockSize()];
byte[] outKey = new byte[keyLen];
byte[] outIv = new byte[suite.getAlgorithmBlockSize()];
assert codec != null;
codec.generateSecureRandom(inKey);
codec.generateSecureRandom(inIv);
codec.generateSecureRandom(outKey);
codec.generateSecureRandom(outIv);
return new CipherOption(suite, inKey, inIv, outKey, outIv);
}
}
}
return null;
}
use of org.apache.hadoop.crypto.CipherOption in project hbase by apache.
the class FanOutOneBlockAsyncDFSOutputSaslHelper method createPBHelper.
private static PBHelper createPBHelper() throws NoSuchMethodException {
Class<?> helperClass;
try {
helperClass = Class.forName("org.apache.hadoop.hdfs.protocolPB.PBHelperClient");
} catch (ClassNotFoundException e) {
LOG.debug("No PBHelperClient class found, should be hadoop 2.7-", e);
helperClass = org.apache.hadoop.hdfs.protocolPB.PBHelper.class;
}
Method convertCipherOptionsMethod = helperClass.getMethod("convertCipherOptions", List.class);
Method convertCipherOptionProtosMethod = helperClass.getMethod("convertCipherOptionProtos", List.class);
return new PBHelper() {
@SuppressWarnings("unchecked")
@Override
public List<CipherOptionProto> convertCipherOptions(List<CipherOption> options) {
try {
return (List<CipherOptionProto>) convertCipherOptionsMethod.invoke(null, options);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
@SuppressWarnings("unchecked")
@Override
public List<CipherOption> convertCipherOptionProtos(List<CipherOptionProto> options) {
try {
return (List<CipherOption>) convertCipherOptionProtosMethod.invoke(null, options);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
};
}
use of org.apache.hadoop.crypto.CipherOption in project hadoop by apache.
the class SaslDataTransferClient method doSaslHandshake.
/**
* This method actually executes the client-side SASL handshake.
*
* @param addr connection address
* @param underlyingOut connection output stream
* @param underlyingIn connection input stream
* @param userName SASL user name
* @param saslProps properties of SASL negotiation
* @param callbackHandler for responding to SASL callbacks
* @return new pair of streams, wrapped after SASL negotiation
* @throws IOException for any error
*/
private IOStreamPair doSaslHandshake(InetAddress addr, OutputStream underlyingOut, InputStream underlyingIn, String userName, Map<String, String> saslProps, CallbackHandler callbackHandler) throws IOException {
DataOutputStream out = new DataOutputStream(underlyingOut);
DataInputStream in = new DataInputStream(underlyingIn);
SaslParticipant sasl = SaslParticipant.createClientSaslParticipant(userName, saslProps, callbackHandler);
out.writeInt(SASL_TRANSFER_MAGIC_NUMBER);
out.flush();
try {
// Start of handshake - "initial response" in SASL terminology.
sendSaslMessage(out, new byte[0]);
// step 1
byte[] remoteResponse = readSaslMessage(in);
byte[] localResponse = sasl.evaluateChallengeOrResponse(remoteResponse);
List<CipherOption> cipherOptions = null;
String cipherSuites = conf.get(DFS_ENCRYPT_DATA_TRANSFER_CIPHER_SUITES_KEY);
if (requestedQopContainsPrivacy(saslProps)) {
// values for future expansion.
if (cipherSuites != null && !cipherSuites.isEmpty()) {
if (!cipherSuites.equals(CipherSuite.AES_CTR_NOPADDING.getName())) {
throw new IOException(String.format("Invalid cipher suite, %s=%s", DFS_ENCRYPT_DATA_TRANSFER_CIPHER_SUITES_KEY, cipherSuites));
}
CipherOption option = new CipherOption(CipherSuite.AES_CTR_NOPADDING);
cipherOptions = Lists.newArrayListWithCapacity(1);
cipherOptions.add(option);
}
}
sendSaslMessageAndNegotiationCipherOptions(out, localResponse, cipherOptions);
// step 2 (client-side only)
SaslResponseWithNegotiatedCipherOption response = readSaslMessageAndNegotiatedCipherOption(in);
localResponse = sasl.evaluateChallengeOrResponse(response.payload);
assert localResponse == null;
// SASL handshake is complete
checkSaslComplete(sasl, saslProps);
CipherOption cipherOption = null;
if (sasl.isNegotiatedQopPrivacy()) {
// Unwrap the negotiated cipher option
cipherOption = unwrap(response.cipherOption, sasl);
if (LOG.isDebugEnabled()) {
if (cipherOption == null) {
// No cipher suite is negotiated
if (cipherSuites != null && !cipherSuites.isEmpty()) {
// the client accepts some cipher suites, but the server does not.
LOG.debug("Client accepts cipher suites {}, " + "but server {} does not accept any of them", cipherSuites, addr.toString());
}
} else {
LOG.debug("Client using cipher suite {} with server {}", cipherOption.getCipherSuite().getName(), addr.toString());
}
}
}
// stream pair.
return cipherOption != null ? createStreamPair(conf, cipherOption, underlyingOut, underlyingIn, false) : sasl.createStreamPair(out, in);
} catch (IOException ioe) {
sendGenericSaslErrorMessage(out, ioe.getMessage());
throw ioe;
}
}
use of org.apache.hadoop.crypto.CipherOption in project hadoop by apache.
the class PBHelperClient method convert.
public static CipherOption convert(HdfsProtos.CipherOptionProto proto) {
if (proto != null) {
CipherSuite suite = null;
if (proto.getSuite() != null) {
suite = convert(proto.getSuite());
}
byte[] inKey = null;
if (proto.getInKey() != null) {
inKey = proto.getInKey().toByteArray();
}
byte[] inIv = null;
if (proto.getInIv() != null) {
inIv = proto.getInIv().toByteArray();
}
byte[] outKey = null;
if (proto.getOutKey() != null) {
outKey = proto.getOutKey().toByteArray();
}
byte[] outIv = null;
if (proto.getOutIv() != null) {
outIv = proto.getOutIv().toByteArray();
}
return new CipherOption(suite, inKey, inIv, outKey, outIv);
}
return null;
}
Aggregations