From 1f52dd3c27a88ba62956937b0842ef4d58d71869 Mon Sep 17 00:00:00 2001 From: chubtub <43381989+chubtub@users.noreply.github.com> Date: Fri, 21 Feb 2020 07:43:40 -0500 Subject: [PATCH] [#217] Support reading conf settings from a json file (#218) * Support reading conf settings from a json file * Add optional RIM attributes * Add xml signature element * New commandline arguments for attributes conf file and privatekey or cert specification * Add fields to satisfy NIST checks * Print generated base rim contents to console also --- settings.gradle | 2 +- tools/tcg_rim_tool/build.gradle | 8 +- tools/tcg_rim_tool/keystore.jks | Bin 0 -> 2233 bytes tools/tcg_rim_tool/rim_fields.json | 41 ++ .../src/main/java/hirs/swid/Main.java | 29 +- .../main/java/hirs/swid/SwidTagConstants.java | 129 ++++ .../main/java/hirs/swid/SwidTagGateway.java | 619 ++++++++++++------ .../main/java/hirs/swid/utils/Commander.java | 145 ++-- 8 files changed, 690 insertions(+), 283 deletions(-) create mode 100644 tools/tcg_rim_tool/keystore.jks create mode 100644 tools/tcg_rim_tool/rim_fields.json diff --git a/settings.gradle b/settings.gradle index 30f5655b..a996fc2d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -7,4 +7,4 @@ include 'TPM_Utils', 'HIRS_AttestationCA', 'HIRS_AttestationCAPortal', 'tpm_module', - 'tools' + 'tools/tcg_rim_tool' diff --git a/tools/tcg_rim_tool/build.gradle b/tools/tcg_rim_tool/build.gradle index b83bedbf..fd331228 100644 --- a/tools/tcg_rim_tool/build.gradle +++ b/tools/tcg_rim_tool/build.gradle @@ -6,13 +6,17 @@ repositories { } dependencies { - testCompile 'org.testng:testng:6.8.8' + compile libs.minimal_json + testCompile libs.testng } jar { manifest { - attributes("Main-Class": "hirs.swid.Main") + attributes("Main-Class": "hirs.swid.Main", + "Class-Path": configurations.runtime.files.collect { "lib/$it.name" }.join(' ') + ) } + from(configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }) {} } uploadArchives { diff --git a/tools/tcg_rim_tool/keystore.jks b/tools/tcg_rim_tool/keystore.jks new file mode 100644 index 0000000000000000000000000000000000000000..0c5bc1d7d79494dc9de2140046c0679e8f626427 GIT binary patch literal 2233 zcmcgt`8U*y8=lV?dqWILs2FR+%-EVj6o$%_Ww_P~V{b4>_6&n!>@;M}QrWXhi0u11 zC|kA=*&{A}-Fv?GeD7cI{o(oHdCvQu^PcB@&+{Iy9j}2vAn*x*zro^$cd~J_wh?3@nli00g)M<^TYC5QGF-4lHQa7!*x-E7qhEJ~<8Y91l!^ zdT=|t`>7DuPnSTC*KSoclL4r%k_=OuUeSHo)PQC9=IngfAH9wu3lpw>MIeedZY*v+ zJ>oV*r&vT$VMtq?*P|~s0kA&~8O+}4j5O$aCo~1fHS?u6<3#vl`XZm|^*FTU9xw?{ z2KwAIdS!N{EzRa$Dn21#s_PU}bs^PHW@B@;C%2x$k!M?DjvA1;YdiIF-^@wne1(cq zf3!xTy#%o)23t~~`rUMYec`;K%V#Zqk)T;qK3DR+TZe)^6;#{Dsx!>_eR6cg$u!>( zN--;RDd@FMM``j*+6C>T_j7z{%%Qn#g)3L;qiaP5ifIijv2mN6hZ*vQ$-n%2dKt|J zxt$o5wbab0x7WMwnk)OnFpm?>XGx`UOY1ZPjKD+M1}iz%Eniv0{i%7eB(839Lf7ZX z+B=!jTINp<%)K-T&cpcLl#z7aIzh?UUh#lm8>>pXe$@FUQGRS>+;Gf7z~`=SLV?8- z9F<%Ca1YyW$Ou@J+@#@*lG}26*t2m{jJ=tu)zhyc11WfhuV|sJ>pu0)Uj>@XsxSC5 zCuxHBq(*I%m6~KBJ3hNNLM+hwdGfsUufks8uIGKfeBoh1rxZfL{%CorTm2%euO_M6 z$ZzzW^{7!f-&g4LSZAx$jcG2Lo-nqS5AC6E?82tB$a(Ncg`5ZOA>D%>z<^yd4~5)-sAF$Nw!-YuVv97&C^lff zyP|Kq;2_$I%GlJ{MEnsfR~}YGNfj!KGKnuQ*zr+8N3?Ew{i5*;B|`8YWJ2Te z86-Pi-whM}*uaH_cYO~YJ0Ph>!v>N%qNVi-D=!biv*Kd3e^a;S4qsH_a#x(X7Pw2B zv?O%#LyL4xVLY8vsb(B~$dF}IA}#4z!PJsad;6quj63~X+_<~wuE({FDjA*1U$plR z6rXR41{_QmEBnR2&AW;iIX-);Ma+N2$JsExf8wDUrb@bmcqZsHO+bL6)8l{bai%~v znxvW*X-%P~M}0^LwUW6}QH2}>XWS@VYw?qKvkA>~<0S1lEWR7Aa*WFvI^|N)%IGxD%-J3##Smc<))D1qV(|FhhorBm1TS7lp*qRUo8w0LSAOT-Xo<-Rj z*gn=mPVP@JTr;CF@hTyE(V%*Qc;Z}!NZ&H=QV1|ax}^7X&hPv}-Gev63j!*U)C0ww z9iQiDn?0&i*4h5eKntbtS>F2d;f+`sl74|Y`%ul~s#o#F6!~s1NV#6;;-$~Un9D14 zNR)}4YvY9cJ?@*2$0VV8-j=HoYF@hCC285-LI-N4LAPh>E43^-vPzTHo#ALchMX;N zt+uA^C};hCb;;6C4pW_V^Y1e=Cj`X4kqZfP%v#$iYDTJ(csuIHzr&IK4{3P>8U&(y zgdow`BS>J~3_36X219VyZb~Ac49u58v_kfv0KiHQLg10C2xbO49E1S|#_1zZpTy@0 zVS+K@2#y42Pr^S6%QvBDsB_C&XTdgx$`R(2ki z?jDwi^Jkza1OkadBNdQWP-v4AiaepR|E2%0F-U;WzYREf4|F7e9fTkOEMO7GjYA9I@&1JY!1Ey^uPX?y;8VQ9M{JR)89r!>ZOF2JPLXce59kEg;eianzdk^P^*bN~p*5=2}; z2%PLwfDOU};W~4KhGt?R!{Jh`G169Euw!{>_14u79V;d&Lq z=^f)1E+U4aWDQic*|HAhW&lfo9gRuaEx2qXv?x{{+|Fd)^H4f@b#S|TP}3 entity = objectFactory.createSoftwareIdentityEntity(createEntity(properties)); + JAXBElement entity = objectFactory.createSoftwareIdentityEntity(createEntity(new JsonObject())); swidTag.getEntityOrEvidenceOrLink().add(entity); // we should have resources, there for we need a collection @@ -191,59 +236,68 @@ public class SwidTagGateway { } /** - * This method generates a primary SWID tag from the values in - * resources/swidExamples.properties. + * This method generates a base RIM from the values in a JSON file. * * @param outputFile */ - public void generateSwidTag(final File outputFile) { - Properties properties = new Properties(); - InputStream is = null; + public void generateSwidTag(final String filename) { + SoftwareIdentity swidTag = null; try { - is = SwidTagGateway.class.getClassLoader().getResourceAsStream(SwidTagConstants.EXAMPLE_PROPERTIES); - properties.load(is); - - SoftwareIdentity swidTag = createSwidTag(properties); - - JAXBElement entity = objectFactory.createSoftwareIdentityEntity(createEntity(properties)); + System.out.println("Reading base rim values from " + attributesFile); + BufferedReader jsonIn = Files.newBufferedReader(Paths.get(attributesFile), StandardCharsets.UTF_8); + JsonObject configProperties = Json.parse(jsonIn).asObject(); + //SoftwareIdentity + swidTag = createSwidTag(configProperties.get(SwidTagConstants.SOFTWARE_IDENTITY).asObject()); + //Entity + JAXBElement entity = objectFactory.createSoftwareIdentityEntity( + createEntity(configProperties.get(SwidTagConstants.ENTITY).asObject())); swidTag.getEntityOrEvidenceOrLink().add(entity); - - JAXBElement link = objectFactory.createSoftwareIdentityLink(createLink(properties)); + //Link + JAXBElement link = objectFactory.createSoftwareIdentityLink( + createLink(configProperties.get(SwidTagConstants.LINK).asObject())); swidTag.getEntityOrEvidenceOrLink().add(link); - - JAXBElement meta = objectFactory.createSoftwareIdentityMeta(createSoftwareMeta(properties)); + //Meta + JAXBElement meta = objectFactory.createSoftwareIdentityMeta( + createSoftwareMeta(configProperties.get(SwidTagConstants.META).asObject())); swidTag.getEntityOrEvidenceOrLink().add(meta); - - ResourceCollection payload = createPayload(properties); - Directory directory = createDirectory(properties); - hirs.swid.xjc.File file1 = createFile("Example.com.iotBase.bin", "01.00", "15400"); - hirs.swid.xjc.File file2 = createFile("iotExec.bin", "01.00", "1024"); - directory.getDirectoryOrFile().add(file1); - directory.getDirectoryOrFile().add(file2); + //File + hirs.swid.xjc.File file = createFile( + configProperties.get(SwidTagConstants.PAYLOAD).asObject() + .get(SwidTagConstants.DIRECTORY).asObject() + .get(SwidTagConstants.FILE).asObject()); + //Directory + Directory directory = createDirectory( + configProperties.get(SwidTagConstants.PAYLOAD).asObject() + .get(SwidTagConstants.DIRECTORY).asObject()); + directory.getDirectoryOrFile().add(file); + //Payload + ResourceCollection payload = createPayload( + configProperties.get(SwidTagConstants.PAYLOAD).asObject()); payload.getDirectoryOrFileOrProcess().add(directory); - JAXBElement jaxbPayload = objectFactory.createSoftwareIdentityPayload(payload); + JAXBElement jaxbPayload = + objectFactory.createSoftwareIdentityPayload(payload); swidTag.getEntityOrEvidenceOrLink().add(jaxbPayload); -// JAXBElement swidtagSignature = objectFactory.createSignature(createSignature()); -// swidTag.getEntityOrEvidenceOrLink().add(swidtagSignature); - - JAXBElement jaxbe = objectFactory.createSoftwareIdentity(swidTag); - writeSwidTagFile(jaxbe, outputFile); + } catch (FileNotFoundException e) { + System.out.println("File does not exist or cannot be read: " + e.getMessage()); } catch (IOException e) { - System.out.println("Error reading properties file: "); - e.printStackTrace(); - } finally { - if (is != null) { - try { - is.close(); - } catch (IOException ex) { - // ignore - } - } + System.out.println("Error in file reader: " + e.getMessage()); + } catch (ParseException e) { + System.out.println("Invalid JSON detected at " + e.getLocation().toString()); + } catch (Exception e) { + System.out.println(e.getMessage()); + } + + Document signedSoftwareIdentity = signXMLDocument(objectFactory.createSoftwareIdentity(swidTag)); + System.out.println("Signature core validity: " + validateSignedXMLDocument(signedSoftwareIdentity)); + if (!filename.isEmpty()) { + writeSwidTagFile(signedSoftwareIdentity, new File(filename)); + } else { + writeSwidTagFile(signedSoftwareIdentity, generatedFile); } } - /** + /** * This method validates the .swidtag file at the given filepath against the * schema. A successful validation results in the output of the tag's name * and tagId attributes, otherwise a generic error message is printed. @@ -279,6 +333,31 @@ public class SwidTagGateway { e.printStackTrace(); } } + + /** + * This method writes a Document object out to the file specified by generatedFile. + * + * @param swidTag + */ + public void writeSwidTagFile(Document swidTag, File outputFile) { + try { + OutputStream outStream = new FileOutputStream(outputFile); + TransformerFactory tf = TransformerFactory.newInstance(); + Transformer transformer = tf.newTransformer(); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); + Source source = new DOMSource(swidTag); + System.out.println("Writing to file: " + outputFile.getName()); + transformer.transform(source, new StreamResult(outStream)); + transformer.transform(source, new StreamResult(System.out)); + } catch (FileNotFoundException e) { + System.out.println("Unable to write to file: " + e.getMessage()); + } catch (TransformerConfigurationException e) { + System.out.println("Error instantiating TransformerFactory class: " + e.getMessage()); + } catch (TransformerException e) { + System.out.println("Error instantiating Transformer class: " + e.getMessage()); + } + } /** * Given an input swidtag at [path] parse any PCRs in the payload into an InputStream object. @@ -298,7 +377,7 @@ public class SwidTagGateway { try { JAXBElement element = (JAXBElement) obj; String elementName = element.getName().getLocalPart(); - if (elementName.equals(PAYLOAD)) { + if (elementName.equals(SwidTagConstants.PAYLOAD)) { ResourceCollection rc = (ResourceCollection) element.getValue(); if (!rc.getDirectoryOrFileOrProcess().isEmpty()) { pcrs = parsePCRs(rc.getDirectoryOrFileOrProcess()); @@ -320,14 +399,29 @@ public class SwidTagGateway { * @param properties the Properties object containing parameters from file * @return SoftwareIdentity object created from the properties */ - private SoftwareIdentity createSwidTag(Properties properties) { + private SoftwareIdentity createSwidTag(JsonObject jsonObject) { SoftwareIdentity swidTag = objectFactory.createSoftwareIdentity(); - swidTag.setName(properties.getProperty(SwidTagConstants.SOFTWARE_IDENTITY_NAME)); - swidTag.setTagId(properties.getProperty(SwidTagConstants.SOFTWARE_IDENTITY_TAGID)); - swidTag.setVersion(properties.getProperty(SwidTagConstants.SOFTWARE_IDENTITY_VERSION)); - swidTag.setCorpus(Boolean.parseBoolean(properties.getProperty(SwidTagConstants.SOFTWARE_IDENTITY_CORPUS))); - swidTag.setPatch(Boolean.parseBoolean(properties.getProperty(SwidTagConstants.SOFTWARE_IDENTITY_PATCH))); - swidTag.setSupplemental(Boolean.parseBoolean(properties.getProperty(SwidTagConstants.SOFTWARE_IDENTITY_SUPPLEMENTAL))); + swidTag.setLang(SwidTagConstants.DEFAULT_ENGLISH); + String name = jsonObject.getString(SwidTagConstants.NAME, ""); + if (!name.isEmpty()) { + swidTag.setName(name); + } + String tagId = jsonObject.getString(SwidTagConstants.TAGID, ""); + if (!tagId.isEmpty()) { + swidTag.setTagId(tagId); + } + swidTag.setTagVersion(new BigInteger(jsonObject.getString(SwidTagConstants.TAGVERSION, "0"))); + String version = jsonObject.getString(SwidTagConstants.VERSION, ""); + if (!version.isEmpty()) { + swidTag.setVersion(version); + } + swidTag.setCorpus(jsonObject.getBoolean(SwidTagConstants.CORPUS, false)); + swidTag.setPatch(jsonObject.getBoolean(SwidTagConstants.PATCH, false)); + swidTag.setSupplemental(jsonObject.getBoolean(SwidTagConstants.SUPPLEMENTAL, false)); + if (!swidTag.isCorpus() && !swidTag.isPatch() + && !swidTag.isSupplemental() && swidTag.getVersion() != "0.0") { + swidTag.setVersionScheme(jsonObject.getString(SwidTagConstants.VERSION_SCHEME, "multipartnumeric")); + } return swidTag; } @@ -339,16 +433,34 @@ public class SwidTagGateway { * @param properties the Properties object containing parameters from file * @return Entity object created from the properties */ - private Entity createEntity(Properties properties) { + private Entity createEntity(JsonObject jsonObject) { + boolean isTagCreator = false; Entity entity = objectFactory.createEntity(); - entity.setName(properties.getProperty(SwidTagConstants.ENTITY_NAME)); - entity.setRegid(properties.getProperty(SwidTagConstants.ENTITY_REGID)); - String[] roles = properties.getProperty(SwidTagConstants.ENTITY_ROLE).split(","); + String name = jsonObject.getString(SwidTagConstants.NAME, ""); + if (!name.isEmpty()) { + entity.setName(name); + } + String[] roles = jsonObject.getString(SwidTagConstants.ROLE, "").split(","); for (int i = 0; i < roles.length; i++) { entity.getRole().add(roles[i]); + if (roles[i].equals("tagCreator")) { + isTagCreator = true; + } + } + if (isTagCreator) { + String regid = jsonObject.getString(SwidTagConstants.REGID, ""); + if (regid.isEmpty()) { + //throw exception that regid is required + } else { + entity.setRegid(regid); + } + } else { + entity.setRegid(jsonObject.getString(SwidTagConstants.REGID, "invalid.unavailable")); + } + String thumbprint = jsonObject.getString(SwidTagConstants.THUMBPRINT, ""); + if (!thumbprint.isEmpty()) { + entity.setThumbprint(thumbprint); } - entity.setThumbprint(properties.getProperty(SwidTagConstants.ENTITY_THUMBPRINT)); - return entity; } @@ -358,10 +470,16 @@ public class SwidTagGateway { * @param properties the Properties object containing parameters from file * @return Link element created from the properties */ - private Link createLink(Properties properties) { + private Link createLink(JsonObject jsonObject) { Link link = objectFactory.createLink(); - link.setHref(properties.getProperty(SwidTagConstants.LINK_HREF)); - link.setRel(properties.getProperty(SwidTagConstants.LINK_REL)); + String href = jsonObject.getString(SwidTagConstants.HREF, ""); + if (!href.isEmpty()) { + link.setHref(href); + } + String rel = jsonObject.getString(SwidTagConstants.REL, ""); + if (!rel.isEmpty()) { + link.setRel(rel); + } return link; } @@ -372,85 +490,95 @@ public class SwidTagGateway { * @param properties the Properties object containing parameters from file * @return the Meta element created from the properties */ - private SoftwareMeta createSoftwareMeta(Properties properties) { + private SoftwareMeta createSoftwareMeta(JsonObject jsonObject) { SoftwareMeta softwareMeta = objectFactory.createSoftwareMeta(); Map attributes = softwareMeta.getOtherAttributes(); - attributes.put(_RIM_PCURILOCAL, properties.getProperty(SwidTagConstants.META_PCURILOCAL)); - attributes.put(_RIM_BINDINGSPEC, properties.getProperty(SwidTagConstants.META_BINDINGSPEC)); - attributes.put(_RIM_BINDINGSPECVERSION, properties.getProperty(SwidTagConstants.META_BINDINGSPECVERSION)); - attributes.put(_RIM_PLATFORMMANUFACTURERID, properties.getProperty(SwidTagConstants.META_PLATFORMMANUFACTURERID)); - attributes.put(_RIM_PLATFORMMANUFACTURERSTR, properties.getProperty(SwidTagConstants.META_PLATFORMMANUFACTURERSTR)); - attributes.put(_RIM_PLATFORMMODEL, properties.getProperty(SwidTagConstants.META_PLATFORMMODEL)); - attributes.put(_RIM_COMPONENTCLASS, properties.getProperty(SwidTagConstants.META_COMPONENTCLASS)); - attributes.put(_RIM_COMPONENTMANUFACTURER, properties.getProperty(SwidTagConstants.META_COMPONENTMANUFACTURER)); - attributes.put(_RIM_COMPONENTMANUFACTURERID, properties.getProperty(SwidTagConstants.META_COMPONENTMANUFACTURERID)); - attributes.put(_RIM_RIMLINKHASH, properties.getProperty(SwidTagConstants.META_RIMLINKHASH)); + addNonNullAttribute(attributes, SwidTagConstants._COLLOQUIAL_VERSION, jsonObject.getString(SwidTagConstants.COLLOQUIAL_VERSION, "")); + addNonNullAttribute(attributes, SwidTagConstants._EDITION, jsonObject.getString(SwidTagConstants.EDITION, "")); + addNonNullAttribute(attributes, SwidTagConstants._PRODUCT, jsonObject.getString(SwidTagConstants.PRODUCT, "")); + addNonNullAttribute(attributes, SwidTagConstants._REVISION, jsonObject.getString(SwidTagConstants.REVISION, "")); + addNonNullAttribute(attributes, SwidTagConstants._PAYLOAD_TYPE, jsonObject.getString(SwidTagConstants.PAYLOAD_TYPE, "")); + addNonNullAttribute(attributes, SwidTagConstants._PLATFORM_MANUFACTURER_STR, jsonObject.getString(SwidTagConstants.PLATFORM_MANUFACTURER_STR, "")); + addNonNullAttribute(attributes, SwidTagConstants._PLATFORM_MANUFACTURER_ID, jsonObject.getString(SwidTagConstants.PLATFORM_MANUFACTURER_ID, "")); + addNonNullAttribute(attributes, SwidTagConstants._PLATFORM_MODEL, jsonObject.getString(SwidTagConstants.PLATFORM_MODEL, "")); + addNonNullAttribute(attributes, SwidTagConstants._PLATFORM_VERSION, jsonObject.getString(SwidTagConstants.PLATFORM_VERSION, "")); + addNonNullAttribute(attributes, SwidTagConstants._FIRMWARE_MANUFACTURER_STR, jsonObject.getString(SwidTagConstants.FIRMWARE_MANUFACTURER_STR, "")); + addNonNullAttribute(attributes, SwidTagConstants._FIRMWARE_MANUFACTURER_ID, jsonObject.getString(SwidTagConstants.FIRMWARE_MANUFACTURER_ID, "")); + addNonNullAttribute(attributes, SwidTagConstants._FIRMWARE_MODEL, jsonObject.getString(SwidTagConstants.FIRMWARE_MODEL, "")); + addNonNullAttribute(attributes, SwidTagConstants._FIRMWARE_VERSION, jsonObject.getString(SwidTagConstants.FIRMWARE_VERSION, "")); + addNonNullAttribute(attributes, SwidTagConstants._BINDING_SPEC, jsonObject.getString(SwidTagConstants.BINDING_SPEC, "")); + addNonNullAttribute(attributes, SwidTagConstants._BINDING_SPEC_VERSION, jsonObject.getString(SwidTagConstants.BINDING_SPEC_VERSION, "")); + addNonNullAttribute(attributes, SwidTagConstants._PC_URI_LOCAL, jsonObject.getString(SwidTagConstants.PC_URI_LOCAL, "")); + addNonNullAttribute(attributes, SwidTagConstants._PC_URI_GLOBAL, jsonObject.getString(SwidTagConstants.PC_URI_GLOBAL, "")); + addNonNullAttribute(attributes, SwidTagConstants._RIM_LINK_HASH, jsonObject.getString(SwidTagConstants.RIM_LINK_HASH, "")); return softwareMeta; } - /** - * This method creates a Directory from the parameters read in from a properties file. - * - * @param properties the Properties object containing parameters from file - * @return Directory object created from the properties - */ - private Directory createDirectory(Properties properties) { - Directory directory = objectFactory.createDirectory(); - directory.setLocation(properties.getProperty(SwidTagConstants.DIRECTORY_LOCATION)); - directory.setName(properties.getProperty(SwidTagConstants.DIRECTORY_NAME)); - String directoryRoot = properties.getProperty(SwidTagConstants.DIRECTORY_ROOT); - if (!directoryRoot.isEmpty()) { - directory.setRoot(directoryRoot); - } - - return directory; - } - - /** - * This method creates a hirs.swid.xjc.File from a java.nio.File object. - * This method signature is not currently used and may be removed later. - * - * @param file - * @return hirs.swid.xjc.File object from File object - */ - private hirs.swid.xjc.File createFile(File file) { - return createFile(file.getName(), "01.00", Long.toString(file.length())); - } - - /** - * This method creates a hirs.swid.xjc.File from three arguments, then calculates - * and stores its hash as an attribute in itself. - * - * @param filename - * @param location - * @return hirs.swid.xjc.File object from File object - */ - private hirs.swid.xjc.File createFile(String filename, String version, String size) { - hirs.swid.xjc.File file = objectFactory.createFile(); - file.setName(filename); - file.setVersion(version); - file.setSize(new BigInteger(size)); - String hash = HashSwid.get256Hash(file.getName()); - file.getOtherAttributes().put(_SHA256_HASH, hash); - - return file; - } - /** * This method creates a Payload from the parameters read in from a properties file. * * @param properties the Properties object containing parameters from file * @return the Payload object created */ - private ResourceCollection createPayload(Properties properties) { - ResourceCollection rc = objectFactory.createResourceCollection(); + private ResourceCollection createPayload(JsonObject jsonObject) { + ResourceCollection payload = objectFactory.createResourceCollection(); + Map attributes = payload.getOtherAttributes(); + addNonNullAttribute(attributes, SwidTagConstants._N8060_ENVVARPREFIX, jsonObject.getString(SwidTagConstants.PAYLOAD_ENVVARPREFIX, "")); + addNonNullAttribute(attributes, SwidTagConstants._N8060_ENVVARSUFFIX, jsonObject.getString(SwidTagConstants.PAYLOAD_ENVVARSUFFIX, "")); + addNonNullAttribute(attributes, SwidTagConstants._N8060_PATHSEPARATOR, jsonObject.getString(SwidTagConstants.PAYLOAD_PATHSEPARATOR, "")); - rc.getOtherAttributes().put(_N8060_ENVVARPREFIX, properties.getProperty(SwidTagConstants.PAYLOAD_ENVVARPREFIX)); - rc.getOtherAttributes().put(_N8060_ENVVARSUFFIX, properties.getProperty(SwidTagConstants.PAYLOAD_ENVVARSUFFIX)); - rc.getOtherAttributes().put(_N8060_PATHSEPARATOR, properties.getProperty(SwidTagConstants.PAYLOAD_PATHSEPARATOR)); + return payload; + } - return rc; + /** + * This method creates a Directory from the parameters read in from a properties file. + * + * @param properties the Properties object containing parameters from file + * @return Directory object created from the properties + */ + private Directory createDirectory(JsonObject jsonObject) { + Directory directory = objectFactory.createDirectory(); + directory.setName(jsonObject.getString(SwidTagConstants.NAME, "")); + Map attributes = directory.getOtherAttributes(); + addNonNullAttribute(attributes, SwidTagConstants._SUPPORT_RIM_TYPE, jsonObject.getString(SwidTagConstants.SUPPORT_RIM_TYPE, "")); + addNonNullAttribute(attributes, SwidTagConstants._SUPPORT_RIM_FORMAT, jsonObject.getString(SwidTagConstants.SUPPORT_RIM_FORMAT, "")); + addNonNullAttribute(attributes, SwidTagConstants._SUPPORT_RIM_URI_GLOBAL, jsonObject.getString(SwidTagConstants.SUPPORT_RIM_URI_GLOBAL, "")); +/* + directory.setLocation(jsonObject.getString(SwidTagConstants.DIRECTORY_LOCATION)); + String directoryRoot = jsonObject.getString(SwidTagConstants.DIRECTORY_ROOT); + if (!directoryRoot.isEmpty()) { + directory.setRoot(directoryRoot); + } +*/ + return directory; + } + + /** + * This method creates a hirs.swid.xjc.File from three arguments, then calculates + * and stores its hash as an attribute in itself. + * + * @param filename + * @param location + * @return hirs.swid.xjc.File object from File object + */ + private hirs.swid.xjc.File createFile(JsonObject jsonObject) { + hirs.swid.xjc.File file = objectFactory.createFile(); + file.setName(jsonObject.getString(SwidTagConstants.NAME, "")); + file.setSize(new BigInteger(jsonObject.getString(SwidTagConstants.SIZE, "0"))); + Map attributes = file.getOtherAttributes(); + addNonNullAttribute(attributes, _SHA256_HASH, jsonObject.getString(SwidTagConstants.HASH, "")); + addNonNullAttribute(attributes, SwidTagConstants._SUPPORT_RIM_TYPE, jsonObject.getString(SwidTagConstants.SUPPORT_RIM_TYPE, "")); + addNonNullAttribute(attributes, SwidTagConstants._SUPPORT_RIM_FORMAT, jsonObject.getString(SwidTagConstants.SUPPORT_RIM_FORMAT, "")); + addNonNullAttribute(attributes, SwidTagConstants._SUPPORT_RIM_URI_GLOBAL, jsonObject.getString(SwidTagConstants.SUPPORT_RIM_URI_GLOBAL, "")); + + return file; + } + + private void addNonNullAttribute(Map attributes, QName key, String value) { + if (!value.isEmpty()) { + attributes.put(key, value); + } } /** @@ -480,45 +608,130 @@ public class SwidTagGateway { } /** - * This method creates an xml signature based on the xmldsig schema. - * This method is incomplete and not yet implemented. - * - * @return the Signature object created + * This method signs a SoftwareIdentity with an xmldsig in compatibility mode. + * Current assumptions: digest method SHA256, signature method SHA256, enveloped signature */ - private SignatureType createSignature() { - SignatureType signature = objectFactory.createSignatureType(); - SignedInfoType signedInfo = objectFactory.createSignedInfoType(); + private Document signXMLDocument(JAXBElement swidTag) { + Document doc = null; + try { + XMLSignatureFactory sigFactory = XMLSignatureFactory.getInstance("DOM"); + Reference reference = sigFactory.newReference( + "", + sigFactory.newDigestMethod(DigestMethod.SHA256, null), + Collections.singletonList(sigFactory.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)), + null, + null + ); + SignedInfo signedInfo = sigFactory.newSignedInfo( + sigFactory.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec) null), + sigFactory.newSignatureMethod(SwidTagConstants.SIGNATURE_ALGORITHM_RSA_SHA256, null), + Collections.singletonList(reference) + ); + KeyStore keystore = KeyStore.getInstance("JKS"); + keystore.load(new FileInputStream(SwidTagConstants.DEFAULT_KEYSTORE_PATH), SwidTagConstants.DEFAULT_KEYSTORE_PASSWORD.toCharArray()); + KeyStore.PrivateKeyEntry privateKey = (KeyStore.PrivateKeyEntry) keystore.getEntry(SwidTagConstants.DEFAULT_PRIVATE_KEY_ALIAS, + new KeyStore.PasswordProtection(SwidTagConstants.DEFAULT_KEYSTORE_PASSWORD.toCharArray())); + X509Certificate certificate = (X509Certificate) privateKey.getCertificate(); + KeyInfoFactory kiFactory = sigFactory.getKeyInfoFactory(); + ArrayList x509Content = new ArrayList(); + x509Content.add(certificate.getSubjectX500Principal().getName()); + x509Content.add(certificate); + X509Data data = kiFactory.newX509Data(x509Content); + KeyInfo keyinfo = kiFactory.newKeyInfo(Collections.singletonList(data)); - CanonicalizationMethodType canonicalizationMethod = objectFactory.createCanonicalizationMethodType(); - canonicalizationMethod.setAlgorithm("http://www.w3.org/TR/2001/REC-xml-c14n-20010315"); + doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); + marshaller.marshal(swidTag, doc); + DOMSignContext context = new DOMSignContext(privateKey.getPrivateKey(), doc.getDocumentElement()); + XMLSignature signature = sigFactory.newXMLSignature(signedInfo, keyinfo); + signature.sign(context); + } catch (FileNotFoundException e) { + System.out.println("Keystore not found! " + e.getMessage()); + } catch (IOException e) { + System.out.println("Error loading keystore: " + e.getMessage()); + } catch (NoSuchAlgorithmException | KeyStoreException | InvalidAlgorithmParameterException | + ParserConfigurationException | UnrecoverableEntryException e) { + System.out.println(e.getMessage()); + } catch (CertificateException e) { + System.out.println("Certificate error: " + e.getMessage()); + } catch (JAXBException e) { + System.out.println("Error marshaling signed swidtag: " + e.getMessage()); + } catch (MarshalException | XMLSignatureException e) { + System.out.println("Error while signing SoftwareIdentity: " + e.getMessage()); + } - SignatureMethodType signatureMethod = objectFactory.createSignatureMethodType(); - signatureMethod.setAlgorithm("http://www.w3.org/2000/09/xmldsig#rsa-sha512"); + return doc; + } - ReferenceType reference = objectFactory.createReferenceType(); - TransformsType transforms = objectFactory.createTransformsType(); + /** + * This method validates a Document with a signature element. + * + * @param doc + */ + private boolean validateSignedXMLDocument(Document doc) { + boolean isValid = false; + try { + NodeList nodes = doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature"); + if (nodes.getLength() == 0) { + throw new Exception("Signature element not found!"); + } + DOMValidateContext context = new DOMValidateContext(new X509KeySelector(), nodes.item(0)); + XMLSignatureFactory sigFactory = XMLSignatureFactory.getInstance("DOM"); + XMLSignature signature = sigFactory.unmarshalXMLSignature(context); + isValid = signature.validate(context); + } catch (MarshalException | XMLSignatureException e) { + System.out.println(e.getMessage()); + } catch (Exception e) { + System.out.println(e.getMessage()); + } - TransformType transform = objectFactory.createTransformType(); - transform.setAlgorithm("http://www.w3.org/2000/09/xmldsig#enveloped-signature"); - transforms.getTransform().add(transform); + return isValid; + } - DigestMethodType digestMethod = objectFactory.createDigestMethodType(); - digestMethod.setAlgorithm("http://www.w3.org/2000/09/xmldsig#sha256"); + public class X509KeySelector extends KeySelector { + public KeySelectorResult select(KeyInfo keyinfo, + KeySelector.Purpose purpose, + AlgorithmMethod algorithm, + XMLCryptoContext context) throws KeySelectorException { + Iterator keyinfoItr = keyinfo.getContent().iterator(); + while(keyinfoItr.hasNext()) { + XMLStructure element = (XMLStructure) keyinfoItr.next(); + if (element instanceof X509Data) { + X509Data data = (X509Data) element; + Iterator dataItr = data.getContent().iterator(); + while (dataItr.hasNext()) { + Object object = dataItr.next(); + if (object instanceof X509Certificate) { + final PublicKey publicKey = ((X509Certificate) object).getPublicKey(); + if (areAlgorithmsEqual(algorithm.getAlgorithm(), publicKey.getAlgorithm())) { + return new RIMKeySelectorResult(publicKey); + } + } + } + } + } - reference.setTransforms(transforms); - reference.setDigestMethod(digestMethod); - reference.setDigestValue(new byte[10]); + throw new KeySelectorException("No key found!"); + } - signedInfo.setCanonicalizationMethod(canonicalizationMethod); - signedInfo.setSignatureMethod(signatureMethod); - signedInfo.getReference().add(reference); + public boolean areAlgorithmsEqual(String uri, String name) { + if (uri.equals(SwidTagConstants.SIGNATURE_ALGORITHM_RSA_SHA256) && name.equalsIgnoreCase("RSA")) { + return true; + } else { + return false; + } + } - SignatureValueType signatureValue = objectFactory.createSignatureValueType(); - signatureValue.setValue(new byte[10]); + private class RIMKeySelectorResult implements KeySelectorResult { + private Key key; - signature.setSignedInfo(signedInfo); + public RIMKeySelectorResult(Key key) { + this.key = key; + } - return signature; + public Key getKey() { + return key; + } + } } /** @@ -572,8 +785,6 @@ public class SwidTagGateway { is = SwidTagGateway.class.getClassLoader().getResourceAsStream(SwidTagConstants.SCHEMA_URL); SchemaFactory schemaFactory = SchemaFactory.newInstance(SwidTagConstants.SCHEMA_LANGUAGE); Schema schema = schemaFactory.newSchema(new StreamSource(is)); - JAXBContext jaxbContext = JAXBContext.newInstance(SwidTagConstants.SCHEMA_PACKAGE); - Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); unmarshaller.setSchema(schema); jaxbe = (JAXBElement) unmarshaller.unmarshal(input); } catch (SAXException e) { diff --git a/tools/tcg_rim_tool/src/main/java/hirs/swid/utils/Commander.java b/tools/tcg_rim_tool/src/main/java/hirs/swid/utils/Commander.java index 3a5fc006..3b155e65 100644 --- a/tools/tcg_rim_tool/src/main/java/hirs/swid/utils/Commander.java +++ b/tools/tcg_rim_tool/src/main/java/hirs/swid/utils/Commander.java @@ -17,21 +17,24 @@ public class Commander { private static final String CREATE_STRING = "create"; private static final String VERIFY_STRING = "verify"; private static final String HELP_STRING = "help"; - private static final String EXAMPLE_STRING = "example"; private static final String PARSE_STRING = "parse"; - private static final String IN_STRING = "in"; - private static final String OUT_STRING = "out"; - private static final String HASH_STRING = "hash"; + private static final String ATTRIBUTES_STRING = "attributes"; + private static final String KEY_STRING = "key"; + private static final String PRIVATE_KEY_STRING = "privatekey"; + private static final String CERT_STRING = "cert"; private boolean hasArguments = false; private boolean validate = false; private boolean create = false; private boolean parse = false; + private boolean attributesGiven = false; + private boolean keystoreGiven = false; private String validateFile; - private String createInFile; - private String createOutFile; + private String createOutFile = ""; private String parseFile; + private String attributesFile = ""; + private String keystore = ""; private String hashAlg = null; /** @@ -45,31 +48,18 @@ public class Commander { if (hasArguments) { parseArguments(args); } else { - //printHelp(); + printHelp(); } if (create) { - if (!Files.exists(Paths.get(getCreateInFile()))) { - create = false; - printHelp("Input file doesn't exist..."); - } - if (hashAlg == null) { hashAlg = "256"; } - if (!isValidPath(getCreateOutFile())) { - printHelp(String.format("Invalid file path on creation file...(%s)", - getCreateOutFile())); + if (!getCreateOutFile().isEmpty() && !isValidPath(getCreateOutFile())) { + printHelp(String.format("Invalid file path %s!", getCreateOutFile())); } } - - if (validate && create) { - // there maybe a time in which you could validate what you created - // but not right now - // print the help information - printHelp(); - } } /** @@ -95,15 +85,15 @@ public class Commander { case FULL_COMMAND_PREFIX + CREATE_STRING: case COMMAND_PREFIX + "c": create = true; - break; - case COMMAND_PREFIX + IN_STRING: - if (create) { - createInFile = args[++i]; + if (i+1 < args.length && !args[i+1].substring(0,1).equals(COMMAND_PREFIX)) { + createOutFile = args[++i]; } break; - case COMMAND_PREFIX + OUT_STRING: - if (create) { - createOutFile = args[++i]; + case FULL_COMMAND_PREFIX + ATTRIBUTES_STRING: + case COMMAND_PREFIX + "a": + attributesGiven = true; + if (i+1 < args.length && !args[i+1].substring(0,1).equals(COMMAND_PREFIX)) { + attributesFile = args[++i]; } break; case FULL_COMMAND_PREFIX + VERIFY_STRING: @@ -111,27 +101,18 @@ public class Commander { validate = true; validateFile = args[++i]; break; - case FULL_COMMAND_PREFIX + EXAMPLE_STRING: - case COMMAND_PREFIX + "e": - hasArguments = false; - return; // default is generate - case COMMAND_PREFIX + HASH_STRING: - hashAlg = args[++i]; - break; case FULL_COMMAND_PREFIX + PARSE_STRING: case COMMAND_PREFIX + "p": parse = true; parseFile = args[++i]; break; + case FULL_COMMAND_PREFIX + KEY_STRING: + case COMMAND_PREFIX + "k": + keystore = args[++i]; + break; case FULL_COMMAND_PREFIX + HELP_STRING: case COMMAND_PREFIX + "h": default: - if (Files.exists(Paths.get(args[i]))) { - validate = true; - validateFile = args[i]; - break; - } - printHelp(); } } @@ -146,15 +127,6 @@ public class Commander { return validateFile; } - /** - * Getter for the input create file associated with the create flag - * - * @return - */ - public final String getCreateInFile() { - return createInFile; - } - /** * Getter for the output file for the create flag * @@ -218,7 +190,39 @@ public class Commander { public final String getParseFile() { return parseFile; } - + + /** + * Getter for the attributes file given flag + * @return + */ + public boolean isAttributesGiven() { + return attributesGiven; + } + + /** + * Getter for the file containing attribute key-value pairs + * @return + */ + public String getAttributesFile() { + return attributesFile; + } + + /** + * Getter for the keystore given flag + * @return + */ + public boolean isKeystoreGiven() { + return keystoreGiven; + } + + /** + * Getter for the keystore used for digital signatures + * @return + */ + public String getKeystore() { + return keystore; + } + /** * Default no parameter help method. */ @@ -237,20 +241,29 @@ public class Commander { sb.append(String.format("ERROR: %s\n\n", message)); } sb.append("Usage: HIRS_SwidTag\n"); - sb.append(" -c, --create \tTakes given input in the csv format\n" - + " \t-in \tand produces swidtag payloads.\n" - + " \t-out \tThe -hash argument is optional.\n" - + " \t-hash \n"); - sb.append(" -v, --verify\t\tTakes the provided input file and\n" - + " \t\t\tvalidates it against the schema at\n" - + " \t\t\thttp://standards.iso.org/iso/19770/-2/2015/schema.xsd\n"); - sb.append(" -e, --example\tCreate example swid tag file (generated_swidTag.swidtag)\n"); - sb.append(" -h, --help\t\tPrints the command help information\n"); - sb.append(" \t\tListing no command with no argument will\n" - + " \t\t\tcreate an example tag file\n"); - sb.append(" \t\tValidate the given file argument\n"); - sb.append(" -p, --parse\t\tParse a swidtag's payload\n" - + " \t\tInput swidtag"); + sb.append(" -c, --create \t\tCreate a base rim and write to\n" + + " \t\t\t\tthe given file. If no file is given the default is\n" + + " \t\t\t\tgenerated_swidTag.swidtag\n\n"); + sb.append(" -a, --attributes \tSpecify the JSON file that contains\n" + + " \t\t\t\tthe xml attributes to add to the RIM\n\n"); + sb.append(" -v, --verify\t\t\tTakes the provided input file and\n" + + " \t\t\t\tvalidates it against the schema at\n" + + " \t\t\t\thttp://standards.iso.org/iso/19770/-2/2015/schema.xsd\n\n"); + sb.append(" -p, --parse \t\tParse the given swidtag's payload\n\n"); +/* sb.append(" -k, --key\t\t\tSpecify the credential and its location to use\n" + + " \t-privatekey \tfor digital signatures\n" + + " \t-cert \n\n"); +*/ sb.append(" -h, --help, \tPrints this command help information.\n"); + sb.append(" \t\t\t\tListing no command arguments will also\n" + + " \t\t\t\tprint this help text.\n\n"); + sb.append("Example commands: \n" + + " Create a base rim from the default attribute file and write the rim\n" + + " to generated_swidTag.swidtag:\n\n" + + " \t\tjava -jar tcg_rim_tool-1.0.jar -c\n\n" + + " Create a base rim from the values in config.json and write the rim\n" + + " to base_rim.swidtag:\n\n" + + " \t\tjava -jar tcg_rim_tool-1.0.jar -c base_rim.swidtag -a config.json\n\n" + + " "); System.out.println(sb.toString()); System.exit(1);