def chain(self, key: CryptoString, rotate_optional: bool) -> RetVal: '''Creates a new UserEntry object with new keys and a custody signature. It requires the previous contact request signing key passed as an CryptoString. The new keys are returned in CryptoString format using the following fields: entry sign.public / sign.private -- primary signing keypair crsign.public / crsign.private -- contact request signing keypair crencrypt.public / crencrypt.private -- contact request encryption keypair encrypt.public / encrypt.private -- general-purpose public encryption keypair altencrypt.public / altencrypt.private -- alternate public encryption keypair Note that the last two keys are not required to be updated during entry rotation so that they can be rotated on a different schedule from the other keys. These fields are only returned if there are no errors. ''' if key.prefix != 'ED25519': return RetVal(BadParameterValue, f'wrong key type {key.prefix}') status = self.is_compliant() if status.error(): return status new_entry = UserEntry() new_entry.fields = self.fields.copy() try: index = int(new_entry.fields['Index']) new_entry.fields['Index'] = str(index + 1) except Exception: return RetVal(BadData, 'invalid entry index') out = RetVal() skey = SigningPair() crskey = SigningPair() crekey = EncryptionPair() out['sign.public'] = skey.get_public_key() out['sign.private'] = skey.get_private_key() out['crsign.public'] = crskey.get_public_key() out['crsign.private'] = crskey.get_private_key() out['crencrypt.public'] = crekey.get_public_key() out['crencrypt.private'] = crekey.get_private_key() new_entry.fields['Contact-Request-Verification-Key'] = out[ 'crsign.public'] new_entry.fields['Contact-Request-Encryption-Key'] = out[ 'crencrypt.public'] if rotate_optional: ekey = EncryptionPair() out['encrypt.public'] = ekey.get_public_key() out['encrypt.private'] = ekey.get_private_key() aekey = EncryptionPair() out['altencrypt.public'] = aekey.get_public_key() out['altencrypt.private'] = aekey.get_private_key() new_entry.fields['Public-Encryption-Key'] = out['encrypt.public'] new_entry.fields['Alternate-Encryption-Key'] = out[ 'altencrypt.public'] else: out['encrypt.public'] = '' out['encrypt.private'] = '' out['altencrypt.public'] = '' out['altencrypt.private'] = '' status = new_entry.sign(key, 'Custody') if status.error(): return status out['entry'] = new_entry return out
def chain(self, key: CryptoString, rotate_optional: bool) -> RetVal: '''Creates a new OrgEntry object with new keys and a custody signature. The keys are returned in CryptoString format using the following fields: entry sign.public / sign.private -- primary signing keypair sign.pubhash / sign.privhash -- hashes of the corresponding keys altsign.public / altsign.private -- contact request signing keypair altsign.pubhash / altsign.privhash -- hashes of the corresponding keys encrypt.public / encrypt.private -- general-purpose public encryption keypair encrypt.pubhash / encrypt.privhash -- hashes of the corresponding keys For organization entries, rotating optional keys works a little differently: the primary signing key becomes the secondary signing key in the new entry. When rotation is False, which is recommended only in instances of revocation, the secondary key is removed. Only when rotate_optional is True is the field altsign.private returned. ''' if key.prefix != 'ED25519': return RetVal(BadParameterValue, f'wrong key type {key.prefix}') status = self.is_compliant() if status.error(): return status new_entry = OrgEntry() new_entry.fields = self.fields.copy() try: index = int(new_entry.fields['Index']) new_entry.fields['Index'] = str(index + 1) except Exception: return RetVal(BadData, 'invalid entry index') out = RetVal() skey = SigningPair() ekey = EncryptionPair() out['sign.public'] = skey.get_public_key() out['sign.pubhash'] = skey.get_public_hash() out['sign.private'] = skey.get_private_key() out['sign.privhash'] = skey.get_private_hash() out['encrypt.public'] = ekey.get_public_key() out['encrypt.pubhash'] = ekey.get_public_hash() out['encrypt.private'] = ekey.get_private_key() out['encrypt.privhash'] = ekey.get_private_hash() if rotate_optional: altskey = SigningPair() out['altsign.public'] = altskey.get_public_key() out['altsign.pubhash'] = altskey.get_public_hash() out['altsign.private'] = altskey.get_private_key() out['altsign.privhash'] = altskey.get_private_hash() else: out['altsign.public'] = self.fields['Primary-Verification-Key'] out['altsign.pubhash'] = blake2hash( self.fields['Primary-Verification-Key'].as_string().encode()) out['altsign.private'] = '' status = new_entry.sign(key, 'Custody') if status.error(): return status out['entry'] = new_entry return out