in security/tpm/src/tpm.ts [52:185]
constructor(registrationId?: string, customTpm?: any) {
/*Codes_SRS_NODE_TPM_SECURITY_CLIENT_06_002: [The `customTpm` argument, if present` will be used at the underlying TPM provider. Otherwise the TPM provider will the tss TPM client with a parameter of `false` for simulator use.] */
this._tpm = customTpm ? customTpm : new Tpm(false);
if (registrationId) {
/*Codes_SRS_NODE_TPM_SECURITY_CLIENT_06_001: [The `registrationId` argument if present will be returned as the `registrationId` for subsequent calls to `getRegistrationId`.] */
this._registrationId = registrationId;
}
this._fsm = new machina.Fsm({
initialState: 'disconnected',
states: {
disconnected: {
_onEnter: (callback, err) => {
this._ek = null;
this._srk = null;
this._idKeyPub = null;
if (callback) {
if (err) {
callback(err);
} else {
callback(null, null);
}
}
},
connect: (connectCallback) => this._fsm.transition('connecting', connectCallback),
getEndorsementKey: (callback) => {
this._fsm.handle('connect', (err, _result) => {
if (err) {
callback(err);
} else {
this._fsm.handle('getEndorsementKey', callback);
}
});
},
getStorageRootKey: (callback) => {
this._fsm.handle('connect', (err, _result) => {
if (err) {
callback(err);
} else {
this._fsm.handle('getStorageRootKey', callback);
}
});
},
signWithIdentity: (dataToSign, callback) => {
this._fsm.handle('connect', (err, _result) => {
if (err) {
callback(err);
} else {
this._fsm.handle('signWithIdentity', dataToSign, callback);
}
});
},
activateIdentityKey: (identityKey, callback) => {
this._fsm.handle('connect', (err, _result) => {
if (err) {
callback(err);
} else {
this._fsm.handle('activateIdentityKey', identityKey, callback);
}
});
}
},
connecting: {
_onEnter: (callback) => {
try {
this._tpm.connect(() => {
this._createPersistentPrimary('EK', tss.Endorsement, TpmSecurityClient._ekPersistentHandle, TpmSecurityClient._ekTemplate, (ekCreateErr: Error, ekPublicKey: TPMT_PUBLIC) => {
if (ekCreateErr) {
/*Codes_SRS_NODE_TPM_SECURITY_CLIENT_06_007: [Any errors from interacting with the TPM hardware will cause in SecurityDeviceError to be returned in the err parameter of the callback.] */
this._fsm.transition('disconnected', callback, ekCreateErr);
} else {
/*Codes_SRS_NODE_TPM_SECURITY_CLIENT_06_006: [The `getEndorsementKey` function shall query the TPM hardware and return the `endorsementKey` in the callback.] */
this._ek = ekPublicKey;
this._createPersistentPrimary('SRK', tss.Owner, TpmSecurityClient._srkPersistentHandle, TpmSecurityClient._srkTemplate, (srkCreateErr: Error, srkPublicKey: TPMT_PUBLIC) => {
if (srkCreateErr) {
/*Codes_SRS_NODE_TPM_SECURITY_CLIENT_06_009: [Any errors from interacting with the TPM hardware will cause in SecurityDeviceError to be returned in the err parameter of the callback.] */
this._fsm.transition('disconnected', callback, srkCreateErr);
} else {
/*Codes_SRS_NODE_TPM_SECURITY_CLIENT_06_008: [The `getStorageRootKey` function shall query the TPM hardware and return the `storageRootKey` in the callback.] */
this._srk = srkPublicKey;
this._readPersistentPrimary('IDENTITY', TpmSecurityClient._idKeyPersistentHandle, (_readIdErr: Error, idkPublicKey: TPMT_PUBLIC) => {
//
// Not any kind of fatal error if we can't retrieve the identity public portion. This device might not have ever been provisioned.
// If there is a signing operation attempted before an activate is attempted, an error will occur.
//
this._idKeyPub = idkPublicKey;
this._fsm.transition('connected', callback);
});
}
});
}
});
});
} catch (err) {
this._fsm.transition('disconnected', callback, err);
}
},
'*': () => this._fsm.deferUntilTransition()
},
connected: {
_onEnter: (callback) => {
callback(null);
},
getEndorsementKey: (callback) => {
callback(null, this._ek.asTpm2B());
},
getStorageRootKey: (callback) => {
callback(null, this._srk.asTpm2B());
},
signWithIdentity: (dataToSign, callback) => {
this._signData(dataToSign, (err: Error, signedData: Buffer) => {
if (err) {
debug('Error from signing data: ' + err);
this._fsm.transition('disconnected', callback, err);
} else {
callback(null, signedData);
}
});
},
activateIdentityKey: (identityKey, callback) => {
this._activateIdentityKey(identityKey, (err: Error) => {
if (err) {
debug('Error from activate: ' + err);
this._fsm.transition('disconnected', callback, err);
} else {
callback(null, null);
}
});
},
}
}
});
this._fsm.on('transition', (data) => debug('TPM security State Machine: ' + data.fromState + ' -> ' + data.toState + ' (' + data.action + ')'));
this._fsm.on('handling', (data) => debug('TPM security State Machine: handling ' + data.inputType));
}