1) Add cleaning up for CERTIFICATE_TABLE and CRL_TABLE in Mongo.
2) Fix random test execution with help of @BeforeClass annotation in CrlResourceTest.
3) Fix SVACE issues.
4) Add new java documentation for public and private methods.
Change-Id: I43b7c2dc814d67d3a53b598f4eddf3c1acc2a94d
Signed-off-by: Andrii Androsov <a.androsov@samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/12177
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: dongik Lee <dongik.lee@samsung.com>
Reviewed-by: Jee Hyeok Kim <jihyeok13.kim@samsung.com>
- Before you run a Accout server, You need to set up following steps.
1) Install MongoDB
2) Install Github certificates for github.com and *.github.com.
-6) Please download: file from http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html: Java Cryptography Extension
- 1.Extract files from zip.
- 2.Place local_policy.jar and US_export_policy.jar files in/usr/lib/jvm/PATH_TO_JDK/jre/lib/security
+5) Please download: file from http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html: Java Cryptography Extension
+ 1.Extract files from zip.
+ 2.Place local_policy.jar and US_export_policy.jar files in/usr/lib/jvm/PATH_TO_JDK/jre/lib/security
#New Serial number
-#Wed Sep 07 17:08:34 EEST 2016
+#Tue Sep 27 16:11:46 EEST 2016
keyGeneratorAlgorithm=ECDSA
notAfterInterval=20
securityProvider=BC
ellipticCurve=secp256r1
+keystoreDir=keystore
keyStoreLocation=keystore{0}certificateStorage.jks
+keystoreType=BKS
nextUpdateInterval=1
signatureAlgorithm=SHA256withECDSA
-keystoreType=BKS
rootOU=OCF Sub CA
-serialNumber=515
+serialNumber=0
rootO=Samsung
-caAlias=uuid\:31313131-3131-3131-3131-313131313131
subjectName=uuid\:31313131-3131-3131-3131-313131313131
+caAlias=uuid\:31313131-3131-3131-3131-313131313131
password=PASSWORD
rootC=KR
*/
public final class CertificateConstants {
+ /**
+ * Properties object is used for loading pre-defined configurations: algorithm names and so on.
+ */
public static final Properties PROPERTIES = new Properties();
/**
* Load properties from specified properties file.
*/
static {
- try {
- PROPERTIES.load(new FileInputStream(Constants.PROPERTIES_FILE_NAME));
+ try (FileInputStream inputStream = new FileInputStream(Constants.PROPERTIES_FILE_NAME)) {
+ PROPERTIES.load(inputStream);
} catch (IOException e) {
Log.e(e.getMessage());
}
}
+ /**
+ * Base 64 encoding constant for comparing request encoding.
+ */
public static final String BASE_64 = "oic.sec.encoding.base64";
+ /**
+ * Der encoding constant for comparing request encoding.
+ */
public static final String DER = "oic.sec.encoding.der";
+ /**
+ * Name of security provider, load from properties.
+ */
public static final String SECURITY_PROVIDER = PROPERTIES.getProperty("securityProvider");
+ /**
+ * Not after interval for X509Certificate generation, load from properties.
+ */
public static final String NOT_AFTER_INTERVAL = PROPERTIES.getProperty("notAfterInterval");
+ /**
+ * Next Update interval. is used for generation X509CRL, load from properties.
+ */
public static final String NEXT_UPDATE_INTERVAL = PROPERTIES.getProperty("nextUpdateInterval");
+ /**
+ * Signature algorithm, is used for signing certificates and CRLs, load from properties.
+ */
public static final String SIGNATURE_ALGORITHM = PROPERTIES.getProperty("signatureAlgorithm");
+ /**
+ * KeyStore type, is used for private key storage and for root certificate storage
+ */
static final String KEYSTORE_TYPE = PROPERTIES.getProperty("keystoreType");
+ /**
+ * CA Alias name, is used for storing ca certificate to key storage.
+ */
static final String CA_ALIAS = PROPERTIES.getProperty("caAlias");
+ /**
+ * Curve name, is used in signing algorithm for X509 certificate generation.
+ */
static final String CURVE = PROPERTIES.getProperty("ellipticCurve");
+ /**
+ * Key generation algorithm is used for generation private and public keys.
+ */
static final String KEY_GENERATOR_ALGORITHM = PROPERTIES.getProperty("keyGeneratorAlgorithm");
+ /**
+ * Date format, is used to parse date with UTC TIME format for certificate and CRL generation.
+ */
public static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMddHHmmss");
+ /**
+ * String constant is used to create keystore directory.
+ */
+ public static final String KEYSTORE_DIR = PROPERTIES.getProperty("keystoreDir");
+
+ /**
+ * X500Name for ca issuer, is used for issuing personal certificates and CRLs.
+ */
public static final X500Name CA_ISSUER = Utility.getName(PROPERTIES.getProperty("subjectName"),
PROPERTIES.getProperty("rootC"), PROPERTIES.getProperty("rootO"), PROPERTIES.getProperty("rootOU"));
+ /**
+ * Shared AccountDBManager to get rid of repeatable links on the same object.
+ */
public static final AccountDBManager ACCOUNT_DB_MANAGER = AccountDBManager.getInstance();
+ /**
+ * Certificate factory is used during certificate generation process.
+ */
public static CertificateFactory CERTIFICATE_FACTORY;
static {
}
/**
- * Path to keystore file
+ * Path to keystore file, retrieved from properties file.
*/
public static final File KEYSTORE_FILE = new File(MessageFormat.
format(PROPERTIES.getProperty("keyStoreLocation"), File.separator));
/**
* Set specified value for specified property.
+ *
* @param property specified property
- * @param value specified property value.
+ * @param value specified property value.
*/
public static void set(String property, String value) {
PROPERTIES.setProperty(property, value);
- try {
- PROPERTIES.store(new FileOutputStream(Constants.PROPERTIES_FILE_NAME), "New Serial number");
+ try (FileOutputStream outputStream = new FileOutputStream(Constants.PROPERTIES_FILE_NAME)) {
+ PROPERTIES.store(outputStream, "New Serial number");
} catch (IOException e) {
Log.e(e.getMessage());
}
}
+ /**
+ * Private constructor makes class non-instantiable utility class.
+ */
private CertificateConstants() {
throw new AssertionError();
}
import java.util.List;
import java.util.Map;
-import static org.iotivity.cloud.accountserver.Constants.CERTIFICATE_TABLE;
-import static org.iotivity.cloud.accountserver.Constants.KEYFIELD_DID;
-import static org.iotivity.cloud.accountserver.Constants.KEYFIELD_REVOKED;
+import static org.iotivity.cloud.accountserver.Constants.*;
import static org.iotivity.cloud.accountserver.resources.credprov.cert.CertificateConstants.ACCOUNT_DB_MANAGER;
/**
* This class is used as DB manager for CertificateTable.
* With help of this class we can save certificate info to DB,
- * retrieve it from DB by specified in constructor device id,
- * updateX509CRL certificate, also it helps us get user Id from Token
+ * retrieve it from DB by specified device id,
+ * update X509 certificate, also it helps us to get user Id from Token
* Table by specified device id.
*/
final class CertificateManager {
private final String deviceId;
/**
- * Constructs certificateMananger with specified device id.
+ * Constructs certificateMananger with specified device id. Initialize payload
+ * as new hash map instance.
+ *
* @param deviceId specified device identifier for this CertificateManager.
*/
CertificateManager(String deviceId) {
}
/**
- * Puts for specified key, specified value to
- * object payload;
- * @param key specified key value
- * @param value specified value
+ * Puts specified value for specified key to payload;
+ *
+ * @param key specified String key value
+ * @param value specified Object value
*/
public void put(String key, Object value) {
payLoad.put(key, value);
}
/**
- * Saves new certificate to DB with specified columns.
+ * Saves certificate information: serial number, not after, to DB with specified columns.
*
* @param serialNumber specified certificate serial number
- * @param notAfter validation date not after
- * @param notBefore validation date not before
+ * @param notAfter validation date not after
+ * @param notBefore validation date not before
*/
void save(BigInteger serialNumber, Date notAfter, Date notBefore) {
ACCOUNT_DB_MANAGER.insertRecord(CERTIFICATE_TABLE,
CERTIFICATE_TABLE_TYPE_CASTING_MANAGER.convertObjectToMap(
new CertificateTable(serialNumber.toString(), notAfter,
- notBefore, deviceId, Utility.getUserID(deviceId), false)));
+ notBefore, deviceId, Utility.getUserID(deviceId), false)));
}
/**
- * Updates certificate table with specified revoked column.
+ * Updates certificate table by revoked column.
+ *
* @param certificateTable certificate to be updated.
- * @param revoked specified value for revoke
+ * @param revoked specified value for revoke
*/
void update(CertificateTable certificateTable, boolean revoked) {
certificateTable.setRevoked(revoked);
}
/**
- * Returns certificate from database, according to specified
- * device id
+ * Returns certificate from database for specified in constructor
+ * device id.
*/
public CertificateTable getCertificate() {
HashMap<String, Object> condition = new HashMap<>();
condition.put(KEYFIELD_REVOKED, false);
List<HashMap<String, Object>> listMap = ACCOUNT_DB_MANAGER.selectRecord(
CERTIFICATE_TABLE, condition);
- if (!listMap.isEmpty()) {
+ if (listMap != null && !listMap.isEmpty()) {
return CERTIFICATE_TABLE_TYPE_CASTING_MANAGER
.convertMaptoObject(
listMap.get(0),
return null;
}
}
-}
+}
\ No newline at end of file
import java.io.IOException;
import java.security.GeneralSecurityException;
+import java.security.PublicKey;
import java.security.Security;
import java.security.cert.CRLException;
import java.security.cert.X509Certificate;
private static final Cbor<Map<String, Object>> MAP_CBOR = new Cbor<>();
/**
- * Constructs certificate resourcewith specified prefixes
- */
- public CertificateResource() {
- super(Arrays.asList(PREFIX_OIC, CREDPROV_URI, CERT_URI));
- }
-
- /**
- * Insert BouncyCastleProvider into 0 position in security provider list.
- * Init KeyStore, Generate CA certificate and save it to keyStore.
+ * Inserts BouncyCastleProvider into 0 position in security provider list,
+ * inits KeyStore, generates CA certificate and saves it to keyStore.
*/
static {
Security.insertProviderAt(new BouncyCastleProvider(), 0);
}
}
+ /**
+ * Constructs certificate resource with specified prefixes.
+ */
+ public CertificateResource() {
+ super(Arrays.asList(PREFIX_OIC, CREDPROV_URI, CERT_URI));
+ }
+
@Override
public void onDefaultRequestReceived(Device srcDevice, IRequest request)
throws ServerException {
}
/**
- * Handles post requests to this resource
+ * Handles post requests to Certificate Resource.
+ * Request should be with specified format
+ * POST /oic/credprov/cert
+ * {
+ * “di” : “11-22-xx”,
+ * “csr” : {
+ * “encoding” : “oic.sec.encoding.base64”,
+ * “data” : “<Base64 encoded CSR Binary>”
+ * }
+ * }
+ * Method checks encoding, and decodes data by specified encoding if needed.
+ *
+ * Method issus a certificate including User UUID in extension field,
+ * stores issuing information (serial number, validity, device uuid, user uuid) for management (e.g. re-issue).
+ * Response should be in next format for example:
+ * 2.04 CHANGED
+ * {
+ * “di” : “1111-22-xx”,
+ * “cert” : {
+ * “encoding” : “oic.sec.encoding.base64”,
+ * “data” : “<Base64 encoded Cert. Binary>”
+ * },
+ * “certchain” : {
+ * “encoding” : “oic.sec.encoding.base64”,
+ * “data” : “<Base64 encoded CA Cert. chain>”
+ * }
+ * }
+ * or returns BAD_REQUEST: 4.0.1 if any exceptions occured.
+ *
* @param request request with payload information.
* @throws ServerException
*/
private IResponse handlePostRequest(IRequest request)
throws ServerException {
- Map<String, Object> payloadData = MAP_CBOR
- .parsePayloadFromCbor(request.getPayload(), HashMap.class);
+ byte[] requestPayload = request.getPayload();
IResponse response = MessageBuilder.createResponse(request, ResponseStatus.BAD_REQUEST);
- Object csr = payloadData.get(Constants.REQ_CSR);
- if (csr != null && csr instanceof Map) {
- Object encoding =((Map<String, Object>)csr).get(ENCODING);
- Object data = ((Map<String, Object>)csr).get(DATA);
- if (encoding != null && encoding instanceof String && data != null && data instanceof byte[]) {
- byte[] csrData = (byte[]) data;
- if (encoding.equals(BASE_64)) {
- csrData = Base64.decode(csrData);
- }
- try {
- CSRParser parser = new CSRParser(csrData);
- String commonName = parser.getCommonName();
- String pattern = "^uuid:(.*)$";
- Pattern r = Pattern.compile(pattern);
- Matcher m = r.matcher(commonName);
- String deviceId = (String) payloadData.get(RESP_DEVICE_ID);
- if (m.find() && m.group(1).equals(deviceId) && parser.isSignatureValid()) {
- CertificateManager certificateManager = new CertificateManager(deviceId);
- CertificateTable certificateTable = certificateManager.getCertificate();
- if (certificateTable != null) {
- try {
- CrlManager.CRL_MANAGER.revoke(certificateTable.getSerialNumber());
- } catch (CRLException | OperatorCreationException e) {
- Log.e(e.getMessage() + e.getClass());
- }
- certificateManager.update(certificateTable, true);
+ if (requestPayload != null) {
+ Map<String, Object> payloadData = MAP_CBOR
+ .parsePayloadFromCbor(requestPayload, HashMap.class);
+ if (payloadData != null) {
+ Object csr = payloadData.get(Constants.REQ_CSR);
+ if (csr != null && csr instanceof Map) {
+ Object encoding = ((Map<String, Object>) csr).get(ENCODING);
+ Object data = ((Map<String, Object>) csr).get(DATA);
+ if (encoding != null && encoding instanceof String && data != null && data instanceof byte[]) {
+ byte[] csrData = (byte[]) data;
+ if (encoding.equals(BASE_64)) {
+ csrData = Base64.decode(csrData);
}
- CertificateExtension extension = new CertificateExtension(Extension.subjectAlternativeName,
- false, new DERSequence(new ASN1Encodable[]
- {new GeneralName(GeneralName.dNSName, Constants.KEYFIELD_USERID + ":" +
- Utility.getUserID(deviceId))}));
- CertificateBuilder certBuilder = new CertificateBuilder(parser.getSubject(),
- parser.getPublicKey(), extension );
try {
- X509Certificate personal = certBuilder.build();
- byte[] encodedCert = personal.getEncoded();
- byte[] encodedCa = CertificateStorage.ROOT_CERTIFICATE.getEncoded();
- if (encoding.equals(CertificateConstants.BASE_64)) {
- encodedCert = Base64.encode(encodedCert);
- encodedCa = Base64.encode(encodedCa);
+ CSRParser parser = new CSRParser(csrData);
+ String commonName = parser.getCommonName();
+ String pattern = "^uuid:(.*)$";
+ Pattern r = Pattern.compile(pattern);
+ Matcher m = r.matcher(commonName);
+ String deviceId = (String) payloadData.get(RESP_DEVICE_ID);
+ if (m.find() && m.group(1).equals(deviceId) && parser.isSignatureValid()) {
+ CertificateManager certificateManager = new CertificateManager(deviceId);
+ CertificateTable certificateTable = certificateManager.getCertificate();
+ if (certificateTable != null) {
+ try {
+ CrlManager.CRL_MANAGER.revoke(certificateTable.getSerialNumber());
+ } catch (CRLException | OperatorCreationException e) {
+ Log.e(e.getMessage() + e.getClass());
+ }
+ certificateManager.update(certificateTable, true);
+ }
+ PublicKey publicKey = parser.getPublicKey();
+ if (publicKey != null) {
+ CertificateExtension extension = new CertificateExtension(Extension.subjectAlternativeName,
+ false, new DERSequence(new ASN1Encodable[]
+ {new GeneralName(GeneralName.dNSName, Constants.KEYFIELD_USERID + ":" +
+ Utility.getUserID(deviceId))}));
+ CertificateBuilder certBuilder = new CertificateBuilder(parser.getSubject(),
+ publicKey, extension);
+ try {
+ X509Certificate personal = certBuilder.build();
+ byte[] encodedCert = personal.getEncoded();
+ byte[] encodedCa = CertificateStorage.ROOT_CERTIFICATE.getEncoded();
+ if (encoding.equals(CertificateConstants.BASE_64)) {
+ encodedCert = Base64.encode(encodedCert);
+ encodedCa = Base64.encode(encodedCa);
+ }
+ certificateManager.put(Constants.RESP_DEVICE_ID, deviceId);
+ certificateManager.put(Constants.CERT, new CSR(encoding.toString(), encodedCert));
+ certificateManager.put(Constants.CERT_CHAIN, new CSR(encoding.toString(), encodedCa));
+ certificateManager.save(personal.getSerialNumber(), personal.getNotAfter(),
+ personal.getNotBefore());
+ response = MessageBuilder.createResponse(request, ResponseStatus.CHANGED,
+ ContentFormat.APPLICATION_CBOR,
+ MAP_CBOR.encodingPayloadToCbor(certificateManager.getPayLoad()));
+ } catch (GeneralSecurityException | OperatorCreationException | CertIOException e) {
+ Log.e(e.getMessage());
+ }
+ }
}
- certificateManager.put(Constants.RESP_DEVICE_ID, deviceId);
- certificateManager.put(Constants.CERT, new CSR(encoding.toString(), encodedCert));
- certificateManager.put(Constants.CERT_CHAIN, new CSR(encoding.toString(), encodedCa));
- certificateManager.save(personal.getSerialNumber(), personal.getNotBefore(),
- personal.getNotAfter());
- response = MessageBuilder.createResponse(request, ResponseStatus.CHANGED,
- ContentFormat.APPLICATION_CBOR,
- MAP_CBOR.encodingPayloadToCbor(certificateManager.getPayLoad()));
- } catch (GeneralSecurityException | OperatorCreationException | CertIOException e) {
+ } catch (IOException e) {
Log.e(e.getMessage());
}
}
- } catch (IOException e) {
- Log.e(e.getMessage());
}
}
}
}
/**
- * This class is used for response
+ * Response utility class.
*/
private static final class CSR {
this.data = data;
}
+ /**
+ * Return encoding.
+ */
public String getEncoding() {
return encoding;
}
+ /**
+ * Retrieves data.
+ */
public byte[] getData() {
return data;
}
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.Extension;
-import org.bouncycastle.cert.CertIOException;
import org.bouncycastle.jce.ECNamedCurveTable;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.OperatorCreationException;
import org.iotivity.cloud.accountserver.x509.cert.CertificateBuilder;
import org.iotivity.cloud.accountserver.x509.cert.CertificateExtension;
+import org.iotivity.cloud.util.Log;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import static org.iotivity.cloud.accountserver.resources.credprov.cert.CertificateConstants.*;
+/**
+ * This class is used for loading and storing key store.
+ * Also it generates CA certificate and puts it to keystore.
+ */
public final class CertificateStorage {
/**
private static final String PASSWORD = PROPERTIES.getProperty("password");
/**
- * Keystore object for save, get data from keystore.
+ * Root private key is used for signing certificates ans CRLs.
*/
- private static KeyStore keyStore;
-
public static PrivateKey ROOT_PRIVATE_KEY;
- public static X509Certificate ROOT_CERTIFICATE;
-
- private CertificateStorage() {
- throw new AssertionError();
- }
-
/**
- * Init KeyStore. If it does not exists, create it and push to KEYSTORE_FILE.
+ * Root certificate, is used for isssuing low level certificates.
*/
- static void init() throws GeneralSecurityException, IOException, OperatorCreationException {
- Files.createDirectories(Paths.get("keystore"));
- keyStore = load(null, null);
- store();
- CertificateStorage.generateCACertificate();
- CertificateStorage.saveCertificatePrivateKey();
- }
+ public static X509Certificate ROOT_CERTIFICATE;
/**
- * Load KeyStore with default keystore file and password.
- *
- * @return KeyStore instance.
+ * Keystore object to save, retrieve ca private key and ca certificate from keystore.
*/
- public static void load() throws GeneralSecurityException, IOException {
- keyStore = load(new FileInputStream(KEYSTORE_FILE), PASSWORD.toCharArray());
- initRoot();
- }
+ private static KeyStore keyStore;
/**
- * Loads KeyStore with defined inputStream object and password.
- *
- * @param is specified inputStream which contains keystore bytes.
- * @param password specified password for opening keystore.
- * @return KeyStore instance.
+ * Private contructor to make this class non-instantiable.
*/
- private static KeyStore load(InputStream is, char[] password) throws IOException, GeneralSecurityException {
- KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE, BouncyCastleProvider.PROVIDER_NAME);
- keyStore.load(is, password);
- return keyStore;
+ private CertificateStorage() {
+ throw new AssertionError();
}
-
/**
- * Stores keyStore to default file KEYSTORE_FILE with default password.
+ * Loads keystore with null paramaters.
+ * Stores it empty version. Generates CA certificate and private key and
+ * saves it to key storage.
*/
- static void store() throws IOException, GeneralSecurityException {
- store(keyStore, new FileOutputStream(KEYSTORE_FILE), PASSWORD.toCharArray());
+ static void init() throws GeneralSecurityException, IOException, OperatorCreationException {
+ Files.createDirectories(Paths.get(KEYSTORE_DIR));
+ keyStore = KeyStore.getInstance(KEYSTORE_TYPE, SECURITY_PROVIDER);
+ keyStore.load(null, null);
+ generate();
}
/**
- * Stores KeyStore to file outputstream with specifie password.
+ * Loads KeyStore intance from created keystore file and with default password.
*
- * @param keyStore
+ * @return KeyStore instance.
*/
- private static void store(KeyStore keyStore, FileOutputStream out, char[] password) throws GeneralSecurityException,
- IOException {
- keyStore.store(out, password);
- out.close();
+ static void load() throws GeneralSecurityException, IOException {
+ keyStore = KeyStore.getInstance(KEYSTORE_TYPE, SECURITY_PROVIDER);
+ try (InputStream inputStream = new FileInputStream(KEYSTORE_FILE)) {
+ keyStore.load(inputStream, PASSWORD.toCharArray());
+ } catch (IOException ioException) {
+ Log.e(ioException.getMessage());
+ }
+ ROOT_PRIVATE_KEY = (PrivateKey) keyStore.getKey(CA_ALIAS, PASSWORD.toCharArray());
+ ROOT_CERTIFICATE = (X509Certificate) keyStore.getCertificate(CA_ALIAS);
}
/**
- * Generates X509Certificate with PublicKey and PrivateKey
+ * Generates CA X509Certificate and private key and stores it to key storage.
*
* @return certificate and private key
*/
- private static void generateCACertificate() throws GeneralSecurityException,
- OperatorCreationException, CertIOException {
+ private static void generate() throws GeneralSecurityException,
+ OperatorCreationException, IOException {
if (ROOT_PRIVATE_KEY == null) {
KeyPairGenerator g = KeyPairGenerator.getInstance(KEY_GENERATOR_ALGORITHM, SECURITY_PROVIDER);
g.initialize(ECNamedCurveTable.getParameterSpec(CURVE), new SecureRandom());
ROOT_CERTIFICATE = new CertificateBuilder(CA_ISSUER, pair.getPublic(),
new CertificateExtension(Extension.basicConstraints, false,
new BasicConstraints(true))).build();
+ keyStore.setCertificateEntry(CA_ALIAS, ROOT_CERTIFICATE);
+ keyStore.setKeyEntry(CA_ALIAS, ROOT_PRIVATE_KEY, PASSWORD.toCharArray(),
+ new Certificate[]{ROOT_CERTIFICATE});
+ store();
}
}
/**
- * Stores certificate and private key to keystore.
+ * Stores keyStore instance to default keystore file with default password.
*/
- private static void saveCertificatePrivateKey() throws GeneralSecurityException, IOException {
- keyStore.setCertificateEntry(CA_ALIAS, ROOT_CERTIFICATE);
- keyStore.setKeyEntry(CA_ALIAS, ROOT_PRIVATE_KEY, PASSWORD.toCharArray(),
- new Certificate[]{ROOT_CERTIFICATE});
- store();
- }
-
- private static void initRoot() throws GeneralSecurityException {
- ROOT_PRIVATE_KEY = (PrivateKey) keyStore.getKey(CA_ALIAS, PASSWORD.toCharArray());
- ROOT_CERTIFICATE = (X509Certificate) keyStore.getCertificate(CA_ALIAS);
+ private static void store() throws IOException, GeneralSecurityException {
+ try (FileOutputStream out = new FileOutputStream(KEYSTORE_FILE)) {
+ keyStore.store(out, PASSWORD.toCharArray());
+ } catch (IOException ioException) {
+ Log.e(ioException.getMessage());
+ }
}
}
import static org.iotivity.cloud.accountserver.x509.crl.CrlIssuer.CRL_ISSUER;
/**
- * Class is used for managing CRLs(creation, revoke, update)
+ * Class is used to manage CRLs. It helps to create,
+ * update CRLS, revoke certificates.
*/
public final class CrlManager {
/**
- * Static manager for CRLs.
- */
- public static CrlManager CRL_MANAGER;
- /**
* Casting manager for working with CRLTable in mongo db
*/
private static TypeCastingManager<CRLTable> castingManager = new TypeCastingManager<>();
- static {
- try {
- CRL_MANAGER = new CrlManager();
- CRL_MANAGER.init();
- } catch (CRLException | IOException | OperatorCreationException e) {
- Log.e(e.getMessage());
- }
- }
-
/**
* X509 CRL presentation.
*/
private X509CRL x509CRL;
+ /**
+ * Static manager for CRLs.
+ */
+ public static final CrlManager CRL_MANAGER = new CrlManager();
+
+ /**
+ * Private constructor to make this class non-instantiable.
+ */
private CrlManager() {
+ try {
+ Calendar calendar = Calendar.getInstance();
+ Date thisUpdate = calendar.getTime();
+ calendar.add(Calendar.DAY_OF_MONTH,
+ Integer.parseInt(NEXT_UPDATE_INTERVAL));
+ byte[] data = CRL_ISSUER.generate(thisUpdate, calendar.getTime(), Collections.emptyList());
+ ACCOUNT_DB_MANAGER.insertRecord(Constants.CRL_TABLE,
+ castingManager.convertObjectToMap(new CRLTable(thisUpdate, new Binary(data))));
+ setX509CRL(data);
+ } catch (CRLException | IOException | OperatorCreationException e) {
+ Log.e(e.getMessage());
+ }
}
/**
- * Revokes specified serial numbers.
+ * Revokes specified serial numbers. Puts them to database.
*
- * @param serialNumber specified var args serial numbers from 0.
+ * @param serialNumbers specified var args serial numbers from 0.
*/
- public void revoke(String... serialNumber) throws CRLException, IOException, OperatorCreationException {
+ public void revoke(String... serialNumbers) throws CRLException, IOException, OperatorCreationException {
if (x509CRL != null) {
update(x509CRL.getThisUpdate(),
CRL_ISSUER.generate(x509CRL.getThisUpdate(), x509CRL.getNextUpdate(),
- x509CRL.getRevokedCertificates(), serialNumber));
+ x509CRL.getRevokedCertificates(), serialNumbers));
}
}
/**
- * Check if last update is before CRL this update.
+ * Checks last update less than crl this update and returns response payload,
+ * including this update, next update, and CRL in DER encoding.
+ */
+ Map<String, Object> getPayload(String lastUpdate) throws ServerException.PreconditionFailedException, CRLException {
+ if (checkLastUpdate(lastUpdate) && x509CRL != null) {
+ Map<String, Object> responsePayload = new HashMap<>();
+ responsePayload.put(Constants.REQ_THIS_UPDATE, DATE_FORMAT.format(x509CRL.getThisUpdate()));
+ responsePayload.put(Constants.REQ_NEXT_UPDATE, DATE_FORMAT.format(x509CRL.getNextUpdate()));
+ responsePayload.put(Constants.REQ_CRL, new CRL(DER, x509CRL.getEncoded()));
+ return responsePayload;
+ }
+ return Collections.emptyMap();
+ }
+
+
+ /**
+ * Checks if last update is before CRL this update.
+ *
* @param lastUpdate specified last update;
* @return true if before and false - otherwise.
*/
- boolean checkLastUpdate(String lastUpdate) {
+ private boolean checkLastUpdate(String lastUpdate) {
boolean checkCondition = false;
try {
if (x509CRL != null) {
return checkCondition;
}
- /**
- * Returns response payload, including this update, next update, and CRL in DER encoding.
- */
- Map<String, Object> getPayload() throws ServerException.PreconditionFailedException, CRLException {
- if (x509CRL != null) {
- Map<String, Object> responsePayload = new HashMap<>();
- responsePayload.put(Constants.REQ_THIS_UPDATE, DATE_FORMAT.format(x509CRL.getThisUpdate()));
- responsePayload.put(Constants.REQ_NEXT_UPDATE, DATE_FORMAT.format(x509CRL.getNextUpdate()));
- responsePayload.put(Constants.REQ_CRL, new CRL(DER, x509CRL.getEncoded()));
- return responsePayload;
- }
- return Collections.emptyMap();
- }
/**
* Updates CRLTable with specified this update and binary CRL data.
*/
void update(Date thisUpdate, byte[] data) throws CRLException {
- CRLTable crlTable = castingManager.convertMaptoObject(
- ACCOUNT_DB_MANAGER.selectRecord(Constants.CRL_TABLE, new HashMap<>()).get(0), new CRLTable());
- crlTable.setThisUpdate(thisUpdate);
- crlTable.setBinaryData(new Binary(data));
- ACCOUNT_DB_MANAGER.updateRecord(Constants.CRL_TABLE, castingManager.convertObjectToMap(crlTable));
- setX509CRL(data);
- }
-
- /**
- * Create CRL with default options;
- */
- private void init() throws CRLException, IOException, OperatorCreationException {
- Calendar calendar = Calendar.getInstance();
- Date thisUpdate = calendar.getTime();
- calendar.add(Calendar.DAY_OF_MONTH,
- Integer.parseInt(NEXT_UPDATE_INTERVAL));
- byte[] data = CRL_ISSUER.generate(thisUpdate, calendar.getTime(), Collections.emptyList());
- ACCOUNT_DB_MANAGER.insertRecord(Constants.CRL_TABLE,
- castingManager.convertObjectToMap(new CRLTable(thisUpdate, new Binary(data))));
- setX509CRL(data);
+ ArrayList<HashMap<String, Object>> crlList = ACCOUNT_DB_MANAGER.selectRecord(Constants.CRL_TABLE,
+ new HashMap<>());
+ if (crlList != null && !crlList.isEmpty()) {
+ CRLTable crlTable = castingManager.convertMaptoObject(crlList.get(0), new CRLTable());
+ crlTable.setThisUpdate(thisUpdate);
+ crlTable.setBinaryData(new Binary(data));
+ ACCOUNT_DB_MANAGER.updateRecord(Constants.CRL_TABLE, castingManager.convertObjectToMap(crlTable));
+ setX509CRL(data);
+ }
}
/**
}
/**
- * Static inner class for CBOR Crl presentation.
+ * Utility class for CBOR Crl presentation.
*/
private static final class CRL {
private final byte[] data;
- public CRL(String encoding, byte[] data) {
+ CRL(String encoding, byte[] data) {
this.encoding = encoding;
this.data = data;
}
return data;
}
}
-
}
import static org.iotivity.cloud.accountserver.resources.credprov.crl.CrlManager.CRL_MANAGER;
/**
- * Class is responsible for handling requests GET and POST for CRL data.
+ * Class is used working with POST and GET requests and
+ * handles CRL requests.
*/
public class CrlResource extends Resource {
}
/**
- * Handles GET request and sends response back to the client.
+ * Method handles GET requests with specified format:
+ * GET /oic/credprov/crl?lu=20170701000000
+ * Checks if “lu” value is not after the latest update.
+ * If so, response with the latest CRL, otherwise response error (e.g. 4.04 Not Found)
+ * And response of next format:
+ * 2.05 CONTENTS
+ * {
+ * “tu” : “20160711000000”,
+ * “nu” : “20161011000000”,
+ * “crl” : {
+ * “encoding” : “oic.sec.encoding.base64”,
+ * “data” : “<Base64 encoded CRL Binary>”
+ * }
+ * }
*/
private IResponse handleGetRequest(IRequest request)
throws ServerException {
IResponse iResponse = MessageBuilder.createResponse(request, ResponseStatus.NOT_FOUND);
if (queryData != null) {
List<String> lastUpdateList = queryData.get(Constants.REQ_LAST_UPDATE);
- if (lastUpdateList != null && !lastUpdateList.isEmpty() &&
- CRL_MANAGER.checkLastUpdate(lastUpdateList.get(0))) {
+ if (lastUpdateList != null && !lastUpdateList.isEmpty()) {
try {
- iResponse = MessageBuilder.createResponse(request, ResponseStatus.CONTENT,
- ContentFormat.APPLICATION_CBOR, MAP_CBOR.encodingPayloadToCbor(CRL_MANAGER.getPayload()));
+ Map<String, Object> payload = CRL_MANAGER.getPayload(lastUpdateList.get(0));
+ if (!payload.isEmpty()) {
+ iResponse = MessageBuilder.createResponse(request, ResponseStatus.CONTENT,
+ ContentFormat.APPLICATION_CBOR, MAP_CBOR.encodingPayloadToCbor(payload));
+ }
} catch (CRLException e) {
Log.e(e.getMessage());
}
}
/**
- * Handles POST requests and sends back CRL data in response.
+ * Handles POST requests of next formats:
+ * POST /oic/credprov/crl
+ * {
+ * “tu” : “20160727000000”,
+ * “nu” : “20161027000000”,
+ * “rcsn” : “123456”
+ * }
+ * AND
+ * POST /oic/credprov/crl
+ * {
+ * “tu” : “20160727000000”,
+ * “nu” : “20161027000000”,
+ * “crl” : {
+ * “encoding” : “oic.sec.encoding.base64”,
+ * “data” : “<Base64 encoded New CRL Binary>”
+ * }
+ * }
+ * And responds back with 2.04 CHANGED if everything is ok, and PRECONDITION_FAILED - otherwise
*/
private IResponse handlePostRequest(IRequest request)
throws ServerException {
- Map<String, Object> payloadData = MAP_CBOR
- .parsePayloadFromCbor(request.getPayload(), HashMap.class);
- Object thisUpdate = payloadData.get(Constants.REQ_THIS_UPDATE);
- Object nextUpdate = payloadData.get(Constants.REQ_NEXT_UPDATE);
+ byte[] requestPayload = request.getPayload();
IResponse response = MessageBuilder.createResponse(request, ResponseStatus.PRECONDITION_FAILED);
- if (thisUpdate != null && thisUpdate instanceof String && nextUpdate != null && nextUpdate instanceof String) {
- Date thisUpdateDate;
- try {
- thisUpdateDate = DATE_FORMAT.parse(thisUpdate.toString());
- DATE_FORMAT.parse(nextUpdate.toString());
- Object reqSerialNumber = payloadData.get(Constants.REQ_SERIAL_NUMBER);
- Object crl = payloadData.get(Constants.REQ_CRL);
- if (reqSerialNumber != null && reqSerialNumber instanceof List) {
- CRL_MANAGER.revoke(((List<String>) reqSerialNumber).toArray(new String[]{}));
- response = MessageBuilder.createResponse(request, ResponseStatus.CHANGED);
- } else if (crl != null && crl instanceof Map) {
- Object encoding = ((Map<String, Object>) crl).get(Constants.ENCODING);
- Object crlData = ((Map<String, Object>) crl).get(Constants.DATA);
- if (encoding != null && encoding instanceof String && crlData != null && crlData instanceof byte[]) {
- try {
- if (encoding.equals(BASE_64)) {
- crlData = Base64.decode((byte[]) crlData);
- }
- CRL_MANAGER.update(thisUpdateDate, (byte[]) crlData);
+ if (requestPayload != null) {
+ Map<String, Object> payloadData = MAP_CBOR
+ .parsePayloadFromCbor(request.getPayload(), HashMap.class);
+ if (payloadData != null) {
+ Object thisUpdate = payloadData.get(Constants.REQ_THIS_UPDATE);
+ Object nextUpdate = payloadData.get(Constants.REQ_NEXT_UPDATE);
+ if (thisUpdate != null && thisUpdate instanceof String && nextUpdate != null && nextUpdate instanceof String) {
+ Date thisUpdateDate;
+ try {
+ thisUpdateDate = DATE_FORMAT.parse(thisUpdate.toString());
+ Object reqSerialNumber = payloadData.get(Constants.REQ_SERIAL_NUMBER);
+ Object crl = payloadData.get(Constants.REQ_CRL);
+ if (reqSerialNumber != null && reqSerialNumber instanceof List) {
+ CRL_MANAGER.revoke(((List<String>) reqSerialNumber).toArray(new String[]{}));
response = MessageBuilder.createResponse(request, ResponseStatus.CHANGED);
- } catch (DecoderException e) {
- Log.e(e.getMessage() + e.getClass());
+ } else if (crl != null && crl instanceof Map) {
+ Object encoding = ((Map<String, Object>) crl).get(Constants.ENCODING);
+ Object crlData = ((Map<String, Object>) crl).get(Constants.DATA);
+ if (encoding != null && encoding instanceof String && crlData != null && crlData instanceof byte[]) {
+ try {
+ if (encoding.equals(BASE_64)) {
+ crlData = Base64.decode((byte[]) crlData);
+ }
+ CRL_MANAGER.update(thisUpdateDate, (byte[]) crlData);
+ response = MessageBuilder.createResponse(request, ResponseStatus.CHANGED);
+ } catch (DecoderException e) {
+ Log.e(e.getMessage() + e.getClass());
+ }
+ }
}
+ } catch (CRLException | IOException | OperatorCreationException | ParseException e) {
+ Log.e(e.getMessage() + e.getClass());
}
}
- } catch (CRLException | IOException | OperatorCreationException | ParseException e) {
- Log.e(e.getMessage() + e.getClass());
}
}
return response;
*/
package org.iotivity.cloud.accountserver.x509.cert;
+import org.bouncycastle.asn1.x500.AttributeTypeAndValue;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.openssl.PEMException;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
* Returns common name from csr subject.
*/
public String getCommonName() {
- return subject.getRDNs(CN)[0].getFirst().getValue().toString();
-
+ AttributeTypeAndValue rdn = subject.getRDNs(CN)[0].getFirst();
+ if (rdn != null) {
+ return rdn.getValue().toString();
+ }
+ return null;
}
/**
/**
* Attribute for X500Name subject.
*/
- private X500Name subject;
+ private final X500Name subject;
/**
* Attribute for public key.
*/
- private PublicKey publicKey;
+ private final PublicKey publicKey;
/**
* Attribute for certificate extension.
*/
- private CertificateExtension extension;
+ private final CertificateExtension extension;
/**
* Constructs certificate builder with specified subject
* public key and certificate extension.
*/
- public CertificateBuilder(X500Name subject,
- PublicKey publicKey, CertificateExtension extension) {
+ public CertificateBuilder(X500Name subject, PublicKey publicKey, CertificateExtension extension) {
this.subject = subject;
this.publicKey = publicKey;
this.extension = extension;
}
/**
- * Builds X509Certificate with default root key.
+ * Builds X509Certificate, issued by CA issuer, with specific subject and publick key
+ * Adds extension during build.
*/
public X509Certificate build() throws CertIOException, GeneralSecurityException, OperatorCreationException {
X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(
Integer.parseInt(NOT_AFTER_INTERVAL));
return calendar.getTime();
}
-
-
}
\ No newline at end of file
/**
* Returns ASN1Encodable attribute value.
- *
- * @return
*/
ASN1Encodable getValue() {
return value;
import static org.iotivity.cloud.accountserver.resources.credprov.cert.CertificateConstants.CA_ISSUER;
/**
- * Class is used for generating CRL with specified parameters.
+ * Class is used for generating CRLs with specified parameters.
*/
public final class CrlIssuer {
/**
public static final CrlIssuer CRL_ISSUER = new CrlIssuer();
/**
- * Creates new instance of CRL issuer.
+ * Private constructor to make class non-instantiable.
*/
private CrlIssuer() {
}
*/
public byte[] generate(Date thisUpdate, Date nextUpdate, Collection<? extends X509CRLEntry> certs,
String... serialNumbers) throws IOException, OperatorCreationException {
- byte[] crl;
X509v2CRLBuilder crlBuilder = new X509v2CRLBuilder(CA_ISSUER,
thisUpdate);
crlBuilder.setNextUpdate(nextUpdate);
for (String serialNumber : serialNumbers) {
crlBuilder.addCRLEntry(new BigInteger(serialNumber), new Date(), 0);
}
- crl = crlBuilder.build(CertificateBuilder.SIGNER_BUILDER.
+ return crlBuilder.build(CertificateBuilder.SIGNER_BUILDER.
build(CertificateStorage.ROOT_PRIVATE_KEY)).getEncoded();
- return crl;
}
+
}
\ No newline at end of file
*/
package org.iotivity.cloud.accountserver.resources.account.credprov.cert;
-import org.bouncycastle.util.encoders.Base64;
import org.iotivity.cloud.accountserver.Constants;
import org.iotivity.cloud.accountserver.db.AccountDBManager;
import org.iotivity.cloud.accountserver.db.TokenTable;
-import org.iotivity.cloud.accountserver.resources.account.credprov.crl.CrlResourceTest;
import org.iotivity.cloud.accountserver.resources.credprov.cert.CertificateConstants;
import org.iotivity.cloud.accountserver.resources.credprov.cert.CertificateResource;
import org.iotivity.cloud.accountserver.resources.credprov.cert.CertificateStorage;
-import org.iotivity.cloud.accountserver.resources.credprov.crl.CrlResource;
import org.iotivity.cloud.accountserver.util.TypeCastingManager;
import org.iotivity.cloud.accountserver.x509.cert.Utility;
import org.iotivity.cloud.base.OICConstants;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.math.BigInteger;
-import java.security.cert.*;
-import java.util.*;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
import java.util.concurrent.CountDownLatch;
-import static org.iotivity.cloud.accountserver.resources.credprov.cert.CertificateConstants.*;
-import static org.junit.Assert.*;
+import static org.iotivity.cloud.accountserver.resources.credprov.cert.CertificateConstants.CERTIFICATE_FACTORY;
+import static org.iotivity.cloud.accountserver.resources.credprov.cert.CertificateConstants.KEYSTORE_FILE;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
public class CertificateResourceTest {
- private static final String COMMON_NAME = "OU=OCF Device CA, O=Samsung, C=KR, CN=uuid:B371C481-38E6-4D47-8320-7688D8A5B58C";
-
+ public static final String COMMON_NAME = "OU=OCF Device CA, O=Samsung, C=KR, CN=uuid:B371C481-38E6-4D47-8320-7688D8A5B58C";
+ public static final String DEVICE_ID = "B371C481-38E6-4D47-8320-7688D8A5B58C";
private static final String CERTIFICATE_URI = OICConstants.CREDPROV_CERT_FULL_URI;
-
- private static final String DEVICE_ID = "B371C481-38E6-4D47-8320-7688D8A5B58C";
-
+ private static CertificateResource certificateResource = new CertificateResource();
+ private static TypeCastingManager<TokenTable> castingManager = new TypeCastingManager<>();
private CoapDevice mMockDevice = mock(CoapDevice.class);
-
private Cbor<HashMap<String, Object>> mCbor = new Cbor<>();
-
private IResponse mResponse = null;
-
private CountDownLatch mLatch = new CountDownLatch(
1);
-
- private static CertificateResource certificateResource = new CertificateResource();
-
private byte[] csr;
- private static TypeCastingManager<TokenTable> castingManager = new TypeCastingManager<>();
-
static void createToken() {
TokenTable certificateTable = new TokenTable();
certificateTable.setDid(DEVICE_ID);
@AfterClass
public static void after() {
KEYSTORE_FILE.delete();
+ AccountDBManager.getInstance().deleteRecord(Constants.CERTIFICATE_TABLE, new HashMap<>());
}
@BeforeClass
Object[] args = invocation.getArguments();
CoapResponse resp = (CoapResponse) args[0];
mResponse = resp;
-
-
mLatch.countDown();
return null;
}
assertTrue(methodCheck(mResponse, ResponseStatus.BAD_REQUEST));
}
- Map<String, Object> payloadData;
-
- Map<String, Object> crlMap;
-
- byte[] data;
-
- X509CRL crlX509;
-
- @Test
- public void testReIssueBase64() throws CRLException, CertificateException {
- IRequest request = csrRequest(DEVICE_ID, CertificateConstants.BASE_64, Base64.encode(csr), RequestMethod.POST, true);
- certificateResource.onDefaultRequestReceived(mMockDevice, request);
- assertTrue(methodCheck(mResponse, ResponseStatus.CHANGED));
-
- Map<String, Object> payloadData = mCbor
- .parsePayloadFromCbor(mResponse.getPayload(), HashMap.class);
- List<BigInteger> serialNumbers = new ArrayList<>();
- Map<String, Object> certMap = (Map<String, Object>) payloadData.get(Constants.CERT);
- InputStream in = new ByteArrayInputStream(Base64.decode((byte[]) certMap.get(Constants.DATA)));
- X509Certificate personaleCert = (X509Certificate) CERTIFICATE_FACTORY.generateCertificate(in);
- serialNumbers.add(personaleCert.getSerialNumber());
- serialNumbers.add(personaleCert.getSerialNumber().subtract(BigInteger.ONE));
-
- request = csrRequest(DEVICE_ID, CertificateConstants.BASE_64, Base64.encode(csr), RequestMethod.POST, true);
- certificateResource.onDefaultRequestReceived(mMockDevice, request);
- assertTrue(methodCheck(mResponse, ResponseStatus.CHANGED));
- payloadData = mCbor
- .parsePayloadFromCbor(mResponse.getPayload(), HashMap.class);
- certMap = (Map<String, Object>) payloadData.get(Constants.CERT);
- in = new ByteArrayInputStream(Base64.decode((byte[]) certMap.get(Constants.DATA)));
- personaleCert = (X509Certificate) CERTIFICATE_FACTORY.generateCertificate(in);
- serialNumbers.add(personaleCert.getSerialNumber());
-
-
- request = csrRequest(DEVICE_ID, CertificateConstants.BASE_64, Base64.encode(csr), RequestMethod.POST, true);
- certificateResource.onDefaultRequestReceived(mMockDevice, request);
- assertTrue(methodCheck(mResponse, ResponseStatus.CHANGED));
- getTestMethodName();
- request = CrlResourceTest.crlRequest(RequestMethod.GET, CrlResourceTest.CRL_URI, CrlResourceTest.CRL_URI_QUERY);
- CrlResource crlResource = new CrlResource();
- crlResource.onDefaultRequestReceived(mMockDevice, request);
- assertTrue(methodCheck(mResponse, ResponseStatus.CONTENT));
- hashmapCheck(mResponse, Constants.ENCODING);
- hashmapCheck(mResponse, Constants.DATA);
- if (mResponse.getPayload() != null) {
- payloadData = mCbor
- .parsePayloadFromCbor(mResponse.getPayload(), HashMap.class);
- crlMap = (Map<String, Object>) payloadData.get(Constants.REQ_CRL);
- data = (byte[]) crlMap.get(Constants.DATA);
- crlX509 = (X509CRL) CERTIFICATE_FACTORY.generateCRL(new ByteArrayInputStream(data));
- }
-
- assertEquals(DER, crlMap.get(Constants.ENCODING));
- assertNotNull(data);
- Set<? extends X509CRLEntry> entries = crlX509.getRevokedCertificates();
- Iterator<? extends X509CRLEntry> iterator = entries.iterator();
- while (iterator.hasNext()) {
- assertTrue(serialNumbers.contains(iterator.next().getSerialNumber()));
- }
- }
-
@Test
public void testMethodNotAllowed() {
IRequest request = csrRequest(DEVICE_ID, CertificateConstants.DER, csr, RequestMethod.GET, true);
return request;
}
- private static class CSR {
+ private boolean methodCheck(IResponse response,
+ ResponseStatus responseStatus) {
+ if (responseStatus == response.getStatus())
+ return true;
+ else
+ return false;
+ }
+
+ private boolean hashmapCheck(IResponse response, String propertyName) {
+ HashMap<String, Object> payloadData = mCbor
+ .parsePayloadFromCbor(response.getPayload(), HashMap.class);
+ if (payloadData.containsKey(propertyName))
+ return true;
+ else
+ return false;
+ }
+
+ public static class CSR {
String encoding;
byte[] data;
}
}
- private boolean methodCheck(IResponse response,
- ResponseStatus responseStatus) {
- if (responseStatus == response.getStatus())
- return true;
- else
- return false;
- }
-
- private boolean hashmapCheck(IResponse response, String propertyName) {
- HashMap<String, Object> payloadData = mCbor
- .parsePayloadFromCbor(response.getPayload(), HashMap.class);
- if (payloadData.containsKey(propertyName))
- return true;
- else
- return false;
- }
-
}
import org.iotivity.cloud.accountserver.Constants;
import org.iotivity.cloud.accountserver.db.AccountDBManager;
import org.iotivity.cloud.accountserver.db.CRLTable;
+import org.iotivity.cloud.accountserver.resources.account.credprov.cert.CertificateResourceTest;
+import org.iotivity.cloud.accountserver.resources.account.credprov.cert.GenerateCSR;
import org.iotivity.cloud.accountserver.resources.credprov.cert.CertificateConstants;
import org.iotivity.cloud.accountserver.resources.credprov.cert.CertificateResource;
import org.iotivity.cloud.accountserver.resources.credprov.cert.CertificateStorage;
import org.iotivity.cloud.accountserver.resources.credprov.crl.CrlResource;
import org.iotivity.cloud.accountserver.util.TypeCastingManager;
import org.iotivity.cloud.accountserver.x509.crl.CrlIssuer;
+import org.iotivity.cloud.base.OICConstants;
import org.iotivity.cloud.base.device.CoapDevice;
import org.iotivity.cloud.base.protocols.IRequest;
import org.iotivity.cloud.base.protocols.IResponse;
import org.iotivity.cloud.base.protocols.enums.RequestMethod;
import org.iotivity.cloud.base.protocols.enums.ResponseStatus;
import org.iotivity.cloud.util.Cbor;
+import org.junit.AfterClass;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.io.ByteArrayInputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.cert.CertificateFactory;
import java.security.cert.X509CRL;
import java.security.cert.X509CRLEntry;
+import java.security.cert.X509Certificate;
import java.text.ParseException;
import java.util.*;
import java.util.concurrent.CountDownLatch;
public static final String CRL_URI_QUERY_CONDITION_FALSE = "lu=21160726210000";
public static final String CRL_URI_QUERY_PARSE_ERROR = "lu=1231212asdzfg4123123123123123";
public static final String[] FOR_FULL_CRL = {Constants.REQ_THIS_UPDATE, Constants.REQ_NEXT_UPDATE, Constants.REQ_CRL};
- public static final PublicKey key = CertificateStorage.ROOT_CERTIFICATE.getPublicKey();
+ public static PublicKey key;
+ static CertificateResource certificateResource;
private static TypeCastingManager<CRLTable> castingManager = new TypeCastingManager<>();
- static {
+ @AfterClass
+ public static void after() {
+ AccountDBManager.getInstance().deleteRecord(Constants.CERTIFICATE_TABLE, new HashMap<>());
+ AccountDBManager.getInstance().deleteRecord(Constants.CRL_TABLE, new HashMap<>());
+ }
+
+ @BeforeClass
+ public static void setUpBefore() {
Security.insertProviderAt(new BouncyCastleProvider(), 0);
- new CertificateResource();
+ certificateResource = new CertificateResource();
+ key = CertificateStorage.ROOT_CERTIFICATE.getPublicKey();
}
/**
payloadData = mCbor
.parsePayloadFromCbor(mResponse.getPayload(), HashMap.class);
crlMap = (Map<String, Object>) payloadData.get(Constants.REQ_CRL);
- data = (byte[]) crlMap.get(Constants.DATA);
- CertificateFactory factory = CertificateFactory.getInstance("X509");
- crlX509 = (X509CRL) factory.generateCRL(new ByteArrayInputStream(data));
+ if (crlMap != null) {
+ data = (byte[]) crlMap.get(Constants.DATA);
+ CertificateFactory factory = CertificateFactory.getInstance("X509");
+ crlX509 = (X509CRL) factory.generateCRL(new ByteArrayInputStream(data));
+ }
}
-
mLatch.countDown();
return null;
}
return SERIAL_NUMBER;
}
+
+ @Test
+ public void testAeIssueBase64() throws Exception {
+ byte[] csr = GenerateCSR.generatePKCS10(CertificateResourceTest.COMMON_NAME, false);
+ IRequest request = csrRequest(CertificateResourceTest.DEVICE_ID, CertificateConstants.BASE_64, Base64.encode(csr), RequestMethod.POST, true);
+ certificateResource.onDefaultRequestReceived(mMockDevice, request);
+ assertTrue(methodCheck(mResponse, ResponseStatus.CHANGED));
+ Map<String, Object> payloadData = mCbor
+ .parsePayloadFromCbor(mResponse.getPayload(), HashMap.class);
+ List<BigInteger> serialNumbers = new ArrayList<>();
+ Map<String, Object> certMap = (Map<String, Object>) payloadData.get(Constants.CERT);
+ InputStream in = new ByteArrayInputStream(Base64.decode((byte[]) certMap.get(Constants.DATA)));
+ X509Certificate personaleCert = (X509Certificate) CERTIFICATE_FACTORY.generateCertificate(in);
+ serialNumbers.add(personaleCert.getSerialNumber());
+ serialNumbers.add(personaleCert.getSerialNumber().subtract(BigInteger.ONE));
+ request = csrRequest(CertificateResourceTest.DEVICE_ID, CertificateConstants.BASE_64, Base64.encode(csr), RequestMethod.POST, true);
+ certificateResource.onDefaultRequestReceived(mMockDevice, request);
+ assertTrue(methodCheck(mResponse, ResponseStatus.CHANGED));
+ payloadData = mCbor
+ .parsePayloadFromCbor(mResponse.getPayload(), HashMap.class);
+ certMap = (Map<String, Object>) payloadData.get(Constants.CERT);
+ in = new ByteArrayInputStream(Base64.decode((byte[]) certMap.get(Constants.DATA)));
+ personaleCert = (X509Certificate) CERTIFICATE_FACTORY.generateCertificate(in);
+ serialNumbers.add(personaleCert.getSerialNumber());
+ request = csrRequest(CertificateResourceTest.DEVICE_ID, CertificateConstants.BASE_64, Base64.encode(csr), RequestMethod.POST, true);
+ certificateResource.onDefaultRequestReceived(mMockDevice, request);
+ assertTrue(methodCheck(mResponse, ResponseStatus.CHANGED));
+ getTestMethodName();
+ request = CrlResourceTest.crlRequest(RequestMethod.GET, CrlResourceTest.CRL_URI, CrlResourceTest.CRL_URI_QUERY);
+ CrlResource crlResource = new CrlResource();
+ crlResource.onDefaultRequestReceived(mMockDevice, request);
+ assertTrue(methodCheck(mResponse, ResponseStatus.CONTENT));
+ hashmapCheck(mResponse, Constants.ENCODING);
+ hashmapCheck(mResponse, Constants.DATA);
+ if (mResponse.getPayload() != null) {
+ payloadData = mCbor
+ .parsePayloadFromCbor(mResponse.getPayload(), HashMap.class);
+ crlMap = (Map<String, Object>) payloadData.get(Constants.REQ_CRL);
+ data = (byte[]) crlMap.get(Constants.DATA);
+ crlX509 = (X509CRL) CERTIFICATE_FACTORY.generateCRL(new ByteArrayInputStream(data));
+ }
+ assertEquals(DER, crlMap.get(Constants.ENCODING));
+ assertNotNull(data);
+ Set<? extends X509CRLEntry> entries = crlX509.getRevokedCertificates();
+ Iterator<? extends X509CRLEntry> iterator = entries.iterator();
+ while (iterator.hasNext()) {
+ assertTrue(serialNumbers.contains(iterator.next().getSerialNumber()));
+ }
+ }
+
+ private IRequest csrRequest(String deviceId, String encoding, byte[] data, RequestMethod method, boolean isEncoded) {
+ IRequest request;
+ HashMap<String, Object> payloadData = new HashMap<>();
+ payloadData.put(Constants.REQ_DEVICE_ID, deviceId);
+ CertificateResourceTest.CSR csr = new CertificateResourceTest.CSR();
+ if (isEncoded) {
+ csr.setEncoding(encoding);
+ csr.setData(data);
+ payloadData.put("csr", csr);
+ }
+ request = MessageBuilder.createRequest(method, OICConstants.CREDPROV_CERT_FULL_URI,
+ null, ContentFormat.APPLICATION_CBOR,
+ mCbor.encodingPayloadToCbor(payloadData));
+ return request;
+ }
+
+
@Test
public void testCrlGetContent() throws Exception {
getTestMethodName();
}
@Test
- public void testX509CRL() {
- Field field;
- Method m;
- try {
- IRequest request = crlRequest(RequestMethod.GET, CRL_URI, CRL_URI_QUERY);
- crlResource.onDefaultRequestReceived(mMockDevice, request);
- assertTrue(methodCheck(mResponse, ResponseStatus.CONTENT));
- field = CrlManager.class.getDeclaredField("x509CRL");
- field.setAccessible(true);
- Object value = field.get(CrlManager.CRL_MANAGER);
- field.set(CrlManager.CRL_MANAGER, null);
- request = crlRequest(RequestMethod.GET, CRL_URI, CRL_URI_QUERY);
- crlResource.onDefaultRequestReceived(mMockDevice, request);
- assertTrue(methodCheck(mResponse, ResponseStatus.NOT_FOUND));
- m = CrlManager.class.getDeclaredMethod("getPayload");
- m.setAccessible(true);
- field.set(CrlManager.CRL_MANAGER, null);
- Object o = m.invoke(CrlManager.CRL_MANAGER);
- assertEquals(Collections.EMPTY_MAP, o);
- field.set(CrlManager.CRL_MANAGER, value);
- } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
- e.printStackTrace();
- } catch (NoSuchFieldException e) {
- e.printStackTrace();
- }
- }
-
- @Test
public void testCrlPreconditionFailedException() throws ParseException, IOException, OperatorCreationException {
getTestMethodName();
getTestMethodName();
getTestMethodName();
IRequest request = crlRequest(RequestMethod.GET, CRL_URI, CRL_URI_QUERY);
crlResource.onDefaultRequestReceived(mMockDevice, request);
+ System.out.println("MRESPONSE" + mResponse.getStatus());
assertTrue(methodCheck(mResponse, ResponseStatus.CONTENT));
String thisUpdate = CertificateConstants.DATE_FORMAT.format(crlX509.getThisUpdate());
String nextUpdate = CertificateConstants.DATE_FORMAT.format(crlX509.getNextUpdate());