Programming certificate store
Neuko provides an abstract class of CertificateStore to make it flexible for developer to choose on how to save and retrieve certificates from the device.
CertificateStore is a class that defines on how the Neuko SDK module saves and retrieves the following certificates:
- Provisioning certificates
- Perpetual certificates
Each of the certificate types consists of 3 types of files:
- Root CA file.
- Chain certificate file.
- Private key file.
For illustration, let’s assume that all Provisioning Certificates is stored in /secured/certificates
/provisioning
directory while Perpetual Certificates will be stored in /secured/certificates/perpetual
.
Info
Downloaded certificates from Neuko Web application have the following filename format:
- Root CA – ProvisioningRootCA.pem
- Chain certificate – account_id–project_id–schema_id-provisioning-certificate.pem.crt
- Private Key – account_id–project_id–schema_id-provisioning-private.pem.crt
import { DeviceIdentifier, CertificateStore } from "@neukolabs/device-sdk-js"; import { readFileSync, writeFileSync } from 'fs'; import path from 'path'; class deviceCertificateStore extends CertificateStore { readonly SECURED_DIR = "./secured/certificates/"; readonly PROVISION_DIR = "provisioning"; readonly PERPETUAL_DIR = "perpetual"; public getBootstrapCertificateAuthority(deviceIdentifier: DeviceIdentifier): Promise<string | Buffer> | string | Buffer { // the path is ./secured/certificates/provisioning/ProvisioningRootCA.pem const filePath = path.join(this.SECURED_DIR, this.PROVISIONING_DIR, "ProvisioningRootCA.pem"); return readFileSync(filePath); } public getBootstrapChainCertificate(deviceIdentifier: DeviceIdentifier): Promise<string | Buffer> | string | Buffer { // the path is ./secured/certificates/provisioning/acc_someid-prj_someid-sch_someid-provisioning-certificate.pem.crt const filePath = path.join(this.SECURED_DIR, this.PROVISIONING_DIR, [deviceIdentifier.accountId, deviceIdentifier.projectId, deviceIdentifier.deviceSchemaId, "provisioning-certificate.pem.crt"].join("-")); return readFileSync(filePath); } public getBootstrapPrivateKey(deviceIdentifier: DeviceIdentifier): Promise<string | Buffer> | string | Buffer { // the path is ./secured/certificates/provisioning/acc_someid-prj_someid-sch_someid-provisioning-private.pem.crt const filePath = path.join(this.SECURED_DIR, this.PROVISIONING_DIR, [deviceIdentifier.accountId, deviceIdentifier.projectId, deviceIdentifier.deviceSchemaId, "provisioning-private.pem.crt"].join("-")); return readFileSync(filePath); } public getPerpetualCertificateAuthority(deviceIdentifier: DeviceIdentifier): Promise<string | Buffer> | string | Buffer { // the path is ./secured/certificates/perpetual/ProvisioningRootCA.pem const filePath = path.join(this.SECURED_DIR, this.PERPETUAL_DIR, "ProvisioningRootCA.pem"); return readFileSync(filePath); } public getPerpetualChainCertificate(deviceIdentifier: DeviceIdentifier): Promise<string | Buffer> | string | Buffer { // the path is ./secured/certificates/perpetual/acc_someid-prj_someid-sch_someid-certificate.pem.crt const filePath = path.join(this.SECURED_DIR, this.PERPETUAL_DIR, [deviceIdentifier.accountId, deviceIdentifier.projectId, deviceIdentifier.deviceSchemaId, "certificate.pem.crt"].join("-")); return readFileSync(filePath); } public getPerpetualPrivateKey(deviceIdentifier: DeviceIdentifier): Promise<string | Buffer> | string | Buffer { // the path is ./secured/certificates/perpetual/acc_someid-prj_someid-sch_someid-private.pem.crt const filePath = path.join(this.SECURED_DIR, this.PERPETUAL_DIR, [deviceIdentifier.accountId, deviceIdentifier.projectId, deviceIdentifier.deviceSchemaId, "private.pem.crt"].join("-")); return readFileSync(filePath); } public savePerpetualCertificateAuthority(deviceIdentifier: DeviceIdentifier, certificate: Promise<string | Buffer> | string | Buffer): Promise<void> | void { const filePath = path.join(this.SECURED_DIR, this.PERPETUAL_DIR, "ProvisioningRootCA.pem"); writeFileSync(filePath, certificate as string | Buffer); } public savePerpetualChainCertificate(deviceIdentifier: DeviceIdentifier, certificate: Promise<string | Buffer> | string | Buffer): Promise<void> | void { const filePath = path.join(this.SECURED_DIR, this.PERPETUAL_DIR, [deviceIdentifier.accountId, deviceIdentifier.projectId, deviceIdentifier.deviceSchemaId, "certificate.pem.crt"].join("-")); writeFileSync(filePath, certificate as string | Buffer); } public savePerpetualPrivateKey(deviceIdentifier: DeviceIdentifier, certificate: Promise<string | Buffer> | string | Buffer): Promise<void> | void { const filePath = path.join(this.SECURED_DIR, this.PERPETUAL_DIR, [deviceIdentifier.accountId, deviceIdentifier.projectId, deviceIdentifier.deviceSchemaId, "private.pem.crt"].join("-")); writeFileSync(filePath, certificate as string | Buffer); } }
import os from neuko.device.model import DeviceIdentifier from neuko.connection.certificateStore import CertificateStore class EdgeGatewayCertificateStore(CertificateStore): PROVISION_DIR = '/opt/secured/cetificates/bootstrap' PERPETUAL_DIR = '/opt/secured/cetificates/perpetual' async def getBootstrapCertificateAuthority(self, deviceIdentifier: DeviceIdentifier) -> str: return os.path.join(self.PROVISION_DIR, 'ProvisioningRootCA.pem') async def getBootstrapChainCertificate(self, deviceIdentifier: DeviceIdentifier) -> str: return os.path.join(self.PROVISION_DIR, f'{deviceIdentifier.accountId}-{deviceIdentifer.projectId}-{deviceIdentifier.deviceSchemaId}-provisioning-certificate.pem.crt') async def getBootstrapPrivateKey(self, deviceIdentifier: DeviceIdentifier) -> str: return os.path.join(self.PROVISION_DIR, f'{deviceIdentifier.accountId}-{deviceIdentifer.projectId}-{deviceIdentifier.deviceSchemaId}-provisioning-private.pem.crt') async def getPerpetualCertificateAuthority(self, deviceIdentifier: DeviceIdentifier) -> str: return os.path.join(self.PERPETUAL_DIR, 'ProvisioningRootCA.pem') async def getPerpetualChainCertificate(self, deviceIdentifier: DeviceIdentifier) -> str: return os.path.join(self.PERPETUAL_DIR, f'{deviceIdentifier.accountId}-{deviceIdentifer.projectId}-{deviceIdentifier.deviceSchemaId}-certificate.pem.crt') async def getPerpetualPrivateKey(self, deviceIdentifier: DeviceIdentifier) -> str: return os.path.join(self.PERPETUAL_DIR, f'{deviceIdentifier.accountId}-{deviceIdentifer.projectId}-{deviceIdentifier.deviceSchemaId}-private.pem.crt') async def savePerpetualCertificateAuthority(self, deviceIdentifier: DeviceIdentifier, certificate: str) -> None: filePath = os.path.join(self.PERPETUAL_DIR, 'ProvisioningRootCA.pem') fd = open(filePath, mode="w") fd.write(certificate) fd.close() async def savePerpetualChainCertificate(self, deviceIdentifier: DeviceIdentifier, certificate: str) -> None: filePath = os.path.join(self.PERPETUAL_DIR, f'{deviceIdentifier.accountId}-{deviceIdentifer.projectId}-{deviceIdentifier.deviceSchemaId}-certificate.pem.crt') fd = open(filePath, mode="w") fd.write(certificate) fd.close() async def savePerpetualPrivateKey(self, deviceIdentifier: DeviceIdentifier, certificate: str) -> None: filePath = os.path.join(self.PERPETUAL_DIR, f'{deviceIdentifier.accountId}-{deviceIdentifer.projectId}-{deviceIdentifier.deviceSchemaId}-private.pem.crt') fd = open(filePath, mode="w") fd.write(certificate) fd.close()