Consolidate timestamp parameters into --timestamp RFC3(339|852). Added a validator class for the parameter arguments.

This commit is contained in:
chubtub 2022-12-29 01:06:18 -05:00
parent 6a84bb50c5
commit b7f9c52fcb
5 changed files with 159 additions and 55 deletions

View File

@ -2,6 +2,9 @@ package hirs.swid;
import hirs.swid.utils.Commander;
import com.beust.jcommander.JCommander;
import hirs.swid.utils.TimestampArgumentValidator;
import java.util.List;
public class Main {
@ -79,16 +82,16 @@ public class Main {
} else {
gateway.setRimEventLog(rimEventLog);
}
String filename = commander.getRfc3852Filename();
if (!filename.isEmpty() && commander.getRfc3339() != null) {
System.out.println("Only one timestamp format can be specified");
System.exit(1);
} else if (!filename.isEmpty()) {
gateway.setTimestampFormat("RFC3852");
gateway.setTimestampArgument(filename);
} else if (commander.getRfc3339() != null) {
gateway.setTimestampFormat("RFC3339");
gateway.setTimestampArgument(commander.getRfc3339());
List<String> timestampArguments = commander.getTimestampArguments();
if (timestampArguments.size() > 0) {
if (new TimestampArgumentValidator(timestampArguments).isValid()) {
gateway.setTimestampFormat(timestampArguments.get(0));
if (timestampArguments.size() > 1) {
gateway.setTimestampArgument(timestampArguments.get(1));
}
} else {
System.exit(1);
}
}
gateway.generateSwidTag(commander.getOutFile());
break;

View File

@ -652,7 +652,7 @@ public class SwidTagGateway {
*/
private XMLObject createXmlTimestamp(Document doc, XMLSignatureFactory sigFactory) {
Element timeStampElement = doc.createElement("TimeStamp");
switch (timestampFormat) {
switch (timestampFormat.toUpperCase()) {
case "RFC3852":
try {
byte[] counterSignature = Base64.getEncoder().encode(

View File

@ -3,6 +3,9 @@ package hirs.swid.utils;
import com.beust.jcommander.Parameter;
import hirs.swid.SwidTagConstants;
import java.util.ArrayList;
import java.util.List;
/**
* Commander is a class that handles the command line arguments for the SWID
* Tags gateway by implementing the JCommander package.
@ -45,15 +48,11 @@ public class Commander {
@Parameter(names = {"-l", "--rimel <path>"}, order = 9,
description = "The TCG eventlog file to use as a support RIM.")
private String rimEventLog = "";
@Parameter(names = {"--rfc3852"}, order = 10,
description = "Add a placeholder for a base 64-encoded RFC3852 countersignature.")
private String rfc3852Filename = "";
@Parameter(names = {"--rfc3339"}, order = 11,
description = "Add a timestamp to the signature that is compliant with RFC3339.")
private boolean rfc3852 = false;
@Parameter(names = {"--rfc3339"}, order = 11, validateWith = Rfc3339Format.class,
description = "Add a timestamp to the signature that is compliant with RFC3339.")
private String rfc3339 = "";
@Parameter(names = {"--timestamp"}, order = 10, variableArity = true,
description = "Add a timestamp to the signature. " +
"Currently only RFC3339 and RFC3852 are supported:\n" +
"\tRFC3339 [yyyy-MM-ddThh:mm:ssZ]\n\tRFC3852 <counterSignature.bin>")
private List<String> timestampArguments = new ArrayList<String>(2);
public boolean isHelp() {
return help;
@ -91,11 +90,9 @@ public class Commander {
public String getRimEventLog() { return rimEventLog; }
public String getRfc3852Filename() { return rfc3852Filename; }
public boolean isRfc3852() { return rfc3852; }
public String getRfc3339() { return rfc3339; }
public List<String> getTimestampArguments() {
return timestampArguments;
}
public String printHelpExamples() {
StringBuilder sb = new StringBuilder();
@ -108,6 +105,11 @@ public class Commander {
sb.append("sign it using privateKey.pem; embed cert.pem in the signature block; ");
sb.append("and write the data to console output:\n\n");
sb.append("\t\t-c base -l support_rim.bin -k privateKey.pem -p cert.pem -e\n\n\n");
sb.append("Create a base RIM using the values in attributes.json; " +
"sign it with the default keystore; add a RFC3852 timestamp; ");
sb.append("and write the data to base_rim.swidtag:\n\n");
sb.append("\t\t-c base -a attributes.json -d -l support_rim.bin " +
"--timestamp RFC3852 counterSignature.bin -o base_rim.swidtag\n\n\n");
sb.append("Validate a base RIM using an external support RIM to override the ");
sb.append("payload file:\n\n");
sb.append("\t\t-v base_rim.swidtag -l support_rim.bin\n\n\n");
@ -138,12 +140,12 @@ public class Commander {
sb.append("Signing credential: (none given)" + System.lineSeparator());
}
sb.append("Event log support RIM: " + this.getRimEventLog() + System.lineSeparator());
if (!this.getRfc3852Filename().isEmpty()) {
sb.append("Timestamp format: RFC3852, " + this.getRfc3852Filename());
} else if (getRfc3339().isEmpty()) {
sb.append("Timestamp format: RFC3339 with generated timestamp");
} else if (!getRfc3339().isEmpty()) {
sb.append("Timestamp format: RFC3339 with timestamp input");
List<String> timestampArguments = this.getTimestampArguments();
if (timestampArguments.size() > 0) {
sb.append("Timestamp format: " + timestampArguments.get(0));
if (timestampArguments.size() == 2) {
sb.append(", " + timestampArguments.get(1));
}
} else {
sb.append("No timestamp included");
}

View File

@ -1,24 +0,0 @@
package hirs.swid.utils;
import com.beust.jcommander.IParameterValidator;
import com.beust.jcommander.ParameterException;
import java.time.Instant;
import java.time.format.DateTimeParseException;
public class Rfc3339Format implements IParameterValidator {
public void validate(String name, String value) throws ParameterException {
if (value != null) {
try {
Instant instant = Instant.parse(value);
} catch (DateTimeParseException e) {
e.printStackTrace();
throw new ParameterException("Parameter " + name + "=" + value +
" is not in valid RFC3339 format; " +
"expected format is yyyy-MM-dd'T'hh:mm:ss'Z'");
}
} else {
return;
}
}
}

View File

@ -0,0 +1,123 @@
package hirs.swid.utils;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.Instant;
import java.time.format.DateTimeParseException;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class TimestampArgumentValidator {
List<String> args;
/**
* This class handles validation of the --timestamp commandline parameter.
* Currently only RFC3339 and RFC3852 formats are supported.
*
* @param args list of arguments from command line
*/
public TimestampArgumentValidator(List<String> args) {
this.args = args;
}
/**
* This is the public access method through which all other methods are called.
*
* @return true if all arguments are valid, false otherwise
*/
public boolean isValid() {
if (isExactlyOneFormat(args)) {
if (args.get(0).equalsIgnoreCase("RFC3852")) {
if (args.size() == 2) {
if (isRfc3852FileValid(args.get(1))) {
return true;
} else {
return false;
}
} else if (args.size() == 1){
System.out.println("Countersignature file is required for RFC3852 timestamps");
return false;
}
} else if (args.get(0).equalsIgnoreCase("RFC3339")) {
if (args.size() == 2) {
if (isRfc3339Format(args.get(1))) {
return true;
} else {
return false;
}
} else if (args.size() == 1) {
return true;
}
} else {
System.out.println("Unsupported timestamp format specified");
return false;
}
}
return false;
}
/**
* This method ensures that exactly one of RFC3339 and RFC3852 are specified.
*
* @param args list of command line arguments
* @return true if exactly one format is specified, false otherwise
*/
private boolean isExactlyOneFormat(List<String> args) {
Pattern pattern = Pattern.compile("(R|r)(F|f)(C|c)(3339|3852)");
String format = args.get(0);
Matcher formatMatcher = pattern.matcher(format);
if (!formatMatcher.matches()) {
System.out.println("Invalid timestamp format specified, expected RFC3339 or RFC3852.");
return false;
}
if (args.size() == 2) {
String argument = args.get(1);
Matcher argumentMatcher = pattern.matcher(argument);
if (argumentMatcher.matches()) {
System.out.println("Exactly one timestamp format must be specified.");
return false;
}
}
return true;
}
/**
* This method verifies a user-given RFC3339 timestamp
*
* @param timestamp the timestamp string
* @return true if valid RFC3339 format, false otherwise
*/
private boolean isRfc3339Format(String timestamp) {
try {
Instant instant = Instant.parse(timestamp);
} catch (DateTimeParseException e) {
System.out.println("Invalid RFC3339 timestamp given: " + timestamp);
return false;
}
return true;
}
/**
* This method verifies the counter signature file
*
* @param file the counter signature
* @return true if file exists and is valid, false otherwise
*/
private boolean isRfc3852FileValid(String file) {
if (file != null && !file.isEmpty()) {
try {
Files.readAllBytes(Paths.get(file));
} catch (IOException e) {
e.printStackTrace();
return false;
}
} else {
System.out.println("RFC3852 requires a filename input of the countersignature file.");
return false;
}
return true;
}
}