8302111: Serialization considerations

Reviewed-by: skoivu, rhalade, weijun, wetmore
This commit is contained in:
Valerie Peng 2024-02-05 22:53:51 +00:00 committed by Jaikiran Pai
parent df7d6e081f
commit 369c573383
21 changed files with 747 additions and 468 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -100,11 +100,9 @@ public class SecretKeySpec implements KeySpec, SecretKey {
* is null or <code>key</code> is null or empty.
*/
public SecretKeySpec(byte[] key, String algorithm) {
if (key == null || algorithm == null) {
throw new IllegalArgumentException("Missing argument");
}
if (key.length == 0) {
throw new IllegalArgumentException("Empty key");
String errMsg = doSanityCheck(key, algorithm);
if (errMsg != null) {
throw new IllegalArgumentException(errMsg);
}
this.key = key.clone();
this.algorithm = algorithm;
@ -266,14 +264,22 @@ public class SecretKeySpec implements KeySpec, SecretKey {
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
String errMsg = doSanityCheck(key, algorithm);
if (errMsg != null) {
throw new InvalidObjectException(errMsg);
}
byte[] temp = key;
this.key = temp.clone();
Arrays.fill(temp, (byte) 0);
}
private static String doSanityCheck(byte[] key, String algorithm) {
String errMsg = null;
if (key == null || algorithm == null) {
throw new InvalidObjectException("Missing argument");
}
this.key = key.clone();
if (key.length == 0) {
throw new InvalidObjectException("Invalid key length");
errMsg = "Missing argument";
} else if (key.length == 0) {
errMsg = "Empty key";
}
return errMsg;
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -102,20 +102,18 @@ public class ChoiceCallback implements Callback, java.io.Serializable {
public ChoiceCallback(String prompt, String[] choices,
int defaultChoice, boolean multipleSelectionsAllowed) {
if (prompt == null || prompt.isEmpty() ||
choices == null || choices.length == 0 ||
defaultChoice < 0 || defaultChoice >= choices.length)
throw new IllegalArgumentException();
choices = (choices == null || choices.length == 0 ? choices :
choices.clone());
String errMsg = doSanityCheck(prompt, choices, defaultChoice,
multipleSelectionsAllowed);
if (errMsg != null) {
throw new IllegalArgumentException(errMsg);
}
this.prompt = prompt;
this.defaultChoice = defaultChoice;
this.multipleSelectionsAllowed = multipleSelectionsAllowed;
this.choices = choices.clone();
for (int i = 0; i < choices.length; i++) {
if (choices[i] == null || choices[i].isEmpty())
throw new IllegalArgumentException();
}
this.choices = choices;
}
/**
@ -183,9 +181,11 @@ public class ChoiceCallback implements Callback, java.io.Serializable {
* @see #getSelectedIndexes
*/
public void setSelectedIndexes(int[] selections) {
if (!multipleSelectionsAllowed)
if (!multipleSelectionsAllowed) {
throw new UnsupportedOperationException();
this.selections = selections == null ? null : selections.clone();
}
this.selections = ((selections == null || selections.length == 0) ?
selections : selections.clone());
}
/**
@ -211,26 +211,35 @@ public class ChoiceCallback implements Callback, java.io.Serializable {
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
choices = (choices == null || choices.length == 0 ?
choices : choices.clone());
String errMsg = doSanityCheck(prompt, choices, defaultChoice,
multipleSelectionsAllowed);
if (errMsg != null) {
throw new InvalidObjectException(errMsg);
}
selections = (selections == null || selections.length == 0 ?
selections : selections.clone());
if (selections != null && selections.length > 1 &&
!multipleSelectionsAllowed) {
throw new InvalidObjectException("Multiple selections not allowed");
}
}
private static String doSanityCheck(String prompt, String[] choices,
int defaultChoice, boolean allowMultiple) {
if ((prompt == null) || prompt.isEmpty() ||
(choices == null) || (choices.length == 0) ||
(defaultChoice < 0) || (defaultChoice >= choices.length)) {
throw new InvalidObjectException(
"Missing/invalid prompt/choices");
return "Missing/invalid prompt/choices";
}
choices = choices.clone();
for (int i = 0; i < choices.length; i++) {
if ((choices[i] == null) || choices[i].isEmpty())
throw new InvalidObjectException("Null/empty choices");
}
if (selections != null) {
selections = selections.clone();
if (!multipleSelectionsAllowed && (selections.length != 1)) {
throw new InvalidObjectException(
"Multiple selections not allowed");
if ((choices[i] == null) || choices[i].isEmpty()) {
return "Null/empty choices value";
}
}
return null;
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -26,6 +26,7 @@
package javax.security.auth.callback;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
/**
@ -189,25 +190,10 @@ public class ConfirmationCallback implements Callback, java.io.Serializable {
*/
public ConfirmationCallback(int messageType,
int optionType, int defaultOption) {
if (messageType < INFORMATION || messageType > ERROR ||
optionType < YES_NO_OPTION || optionType > OK_CANCEL_OPTION)
throw new IllegalArgumentException();
switch (optionType) {
case YES_NO_OPTION:
if (defaultOption != YES && defaultOption != NO)
throw new IllegalArgumentException();
break;
case YES_NO_CANCEL_OPTION:
if (defaultOption != YES && defaultOption != NO &&
defaultOption != CANCEL)
throw new IllegalArgumentException();
break;
case OK_CANCEL_OPTION:
if (defaultOption != OK && defaultOption != CANCEL)
throw new IllegalArgumentException();
break;
String errMsg = doSanityCheck(messageType, optionType, false, null,
defaultOption, null, false);
if (errMsg != null) {
throw new IllegalArgumentException(errMsg);
}
this.prompt = null;
@ -250,21 +236,20 @@ public class ConfirmationCallback implements Callback, java.io.Serializable {
public ConfirmationCallback(int messageType,
String[] options, int defaultOption) {
if (messageType < INFORMATION || messageType > ERROR ||
options == null || options.length == 0 ||
defaultOption < 0 || defaultOption >= options.length)
throw new IllegalArgumentException();
if (options != null) {
options = options.clone();
}
String errMsg = doSanityCheck(messageType, UNSPECIFIED_OPTION, true,
options, defaultOption, null, false);
if (errMsg != null) {
throw new IllegalArgumentException(errMsg);
}
this.prompt = null;
this.messageType = messageType;
this.optionType = UNSPECIFIED_OPTION;
this.defaultOption = defaultOption;
this.options = options.clone();
for (int i = 0; i < options.length; i++) {
if (options[i] == null || options[i].isEmpty())
throw new IllegalArgumentException();
}
this.options = options;
}
/**
@ -304,27 +289,11 @@ public class ConfirmationCallback implements Callback, java.io.Serializable {
public ConfirmationCallback(String prompt, int messageType,
int optionType, int defaultOption) {
if (prompt == null || prompt.isEmpty() ||
messageType < INFORMATION || messageType > ERROR ||
optionType < YES_NO_OPTION || optionType > OK_CANCEL_OPTION)
throw new IllegalArgumentException();
switch (optionType) {
case YES_NO_OPTION:
if (defaultOption != YES && defaultOption != NO)
throw new IllegalArgumentException();
break;
case YES_NO_CANCEL_OPTION:
if (defaultOption != YES && defaultOption != NO &&
defaultOption != CANCEL)
throw new IllegalArgumentException();
break;
case OK_CANCEL_OPTION:
if (defaultOption != OK && defaultOption != CANCEL)
throw new IllegalArgumentException();
break;
String errMsg = doSanityCheck(messageType, optionType, false, null,
defaultOption, prompt, true);
if (errMsg != null) {
throw new IllegalArgumentException(errMsg);
}
this.prompt = prompt;
this.messageType = messageType;
this.optionType = optionType;
@ -369,22 +338,20 @@ public class ConfirmationCallback implements Callback, java.io.Serializable {
public ConfirmationCallback(String prompt, int messageType,
String[] options, int defaultOption) {
if (prompt == null || prompt.isEmpty() ||
messageType < INFORMATION || messageType > ERROR ||
options == null || options.length == 0 ||
defaultOption < 0 || defaultOption >= options.length)
throw new IllegalArgumentException();
if (options != null) {
options = options.clone();
}
String errMsg = doSanityCheck(messageType, UNSPECIFIED_OPTION, true,
options, defaultOption, prompt, true);
if (errMsg != null) {
throw new IllegalArgumentException(errMsg);
}
this.prompt = prompt;
this.messageType = messageType;
this.optionType = UNSPECIFIED_OPTION;
this.defaultOption = defaultOption;
this.options = options.clone();
for (int i = 0; i < options.length; i++) {
if (options[i] == null || options[i].isEmpty())
throw new IllegalArgumentException();
}
this.options = options;
}
/**
@ -491,6 +458,49 @@ public class ConfirmationCallback implements Callback, java.io.Serializable {
return selection;
}
private static String doSanityCheck(int msgType, int optionType,
boolean isUnspecifiedOption, String[] options, int defOption,
String prompt, boolean checkPrompt) {
// validate msgType
if (msgType < INFORMATION || msgType > ERROR) {
return "Invalid msgType";
}
// validate prompt if checkPrompt == true
if (checkPrompt && (prompt == null || prompt.isEmpty())) {
return "Invalid prompt";
}
// validate optionType
if (isUnspecifiedOption) {
if (optionType != UNSPECIFIED_OPTION) {
return "Invalid optionType";
}
// check options
if (options == null || options.length == 0 ||
defOption < 0 || defOption >= options.length) {
return "Invalid options and/or default option";
}
for (String ov : options) {
if (ov == null || ov.isEmpty()) {
return "Invalid option value";
}
}
} else {
if (optionType < YES_NO_OPTION || optionType > OK_CANCEL_OPTION) {
return "Invalid optionType";
}
// validate defOption based on optionType
if ((optionType == YES_NO_OPTION && (defOption != YES &&
defOption != NO)) ||
(optionType == YES_NO_CANCEL_OPTION && (defOption != YES &&
defOption != NO && defOption != CANCEL)) ||
(optionType == OK_CANCEL_OPTION && (defOption != OK &&
defOption != CANCEL))) {
return "Invalid default option";
}
}
return null;
}
/**
* Restores the state of this object from the stream.
*
@ -502,8 +512,15 @@ public class ConfirmationCallback implements Callback, java.io.Serializable {
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
if (options != null) {
options = options.clone();
}
String errMsg = doSanityCheck(messageType, optionType,
(optionType == UNSPECIFIED_OPTION), options, defaultOption,
prompt, false);
if (errMsg != null) {
throw new InvalidObjectException(errMsg);
}
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -178,7 +178,9 @@ public class PasswordCallback implements Callback, java.io.Serializable {
}
if (inputPassword != null) {
inputPassword = inputPassword.clone();
char[] temp = inputPassword;
inputPassword = temp.clone();
Arrays.fill(temp, '0');
cleanable = CleanerFactory.cleaner().register(
this, cleanerFor(inputPassword));
}