Exemplo n.º 1
0
    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
Exemplo n.º 2
0
    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