예제 #1
0
def add(request):
    '''add a key to the keyserver
    '''
    if request.method != 'POST':
        raise Http404

    form = forms.KeyServerAddForm(request.POST)
    c = {}
    try:
        if not form.is_valid():
            raise __AddException
        keytext = form.cleaned_data['keytext']
        # check keytext
        try:
            pgp = pgpdump.AsciiData(keytext.encode("utf-8", "ignore"))
        except:
            raise __AddException
        keys = utils.parse_public_key_packets(pgp)
        keytexts = []
        for data, packets in keys:
            if not utils.is_valid_packets(packets):
                raise __AddException
            keytext = utils.encode_ascii_armor(data)
            keytexts.append(keytext)
        pgpkeys = []
        for keytext in keytexts:
            pgpkey = models.PGPKeyModel.objects.save_to_storage(None, keytext)
            pgpkeys.append(pgpkey)
        c = {
            'pgpkeys': pgpkeys,
        }
    except __AddException:
        content = render(request, 'pgpdb/add_invalid_post.html')
        return HttpResponseBadRequest(content)
    return render(request, 'pgpdb/added.html', c)
예제 #2
0
    def _get_keydata(self, data):
        results = []
        try:
            if "-----BEGIN" in data:
                ak = pgpdump.AsciiData(data)
            else:
                ak = pgpdump.BinaryData(data)
        except TypeError:
            return []

        now = time.time()
        for m in ak.packets():
            if isinstance(m, pgpdump.packet.PublicKeyPacket):
                results.append({
                    "fingerprint":
                    m.fingerprint,
                    "created":
                    m.datetime,
                    "validity":
                    ('e' if (0 < (int(m.expiration_time or 0)) < now) else ''),
                    "keytype_name": (m.pub_algorithm or '').split()[0],
                    "keysize":
                    str(int(1.024 * round(len('%x' % m.modulus) / 0.256))),
                    "uids": [],
                })
            if isinstance(m, pgpdump.packet.UserIDPacket):
                results[-1]["uids"].append({
                    "name": m.user_name,
                    "email": m.user_email
                })

        return results
예제 #3
0
    def _get_keydata(self, data):
        results = {}
        try:
            if "-----BEGIN" in data:
                ak = pgpdump.AsciiData(data)
            else:
                ak = pgpdump.BinaryData(data)
        except TypeError:
            return []

        curfp = None
        for m in ak.packets():
            if isinstance(m, pgpdump.packet.PublicKeyPacket):
                curfp = m.fingerprint
                results[curfp] = {
                    "fingerprint": m.fingerprint,
                    "expires": m.expiration_time,
                    "created": m.datetime,
                    "uids": [],
                }
            if isinstance(m, pgpdump.packet.UserIDPacket):
                results[curfp]["uids"].append({"name": m.user_name, 
                    "email": m.user_email})

        return results
예제 #4
0
def calc_fingerprint(asciiArmored):
    a = pgpdump.AsciiData(asciiArmored)
    p = a.packets()
    try:  # python 2 compatibility
        n = p.next()
    except AttributeError:
        n = next(p)
    fpr = "0x" + n.fingerprint.lower().decode("utf-8")
    log.debug("calc_fingerprint:", fpr)
    return fpr
예제 #5
0
def get_modulus_from_gpg(cert):
    import pgpdump, types
    try:
        data = pgpdump.BinaryData(cert)
    except pgpdump.utils.PgpdumpException:
        data = pgpdump.AsciiData(cert)

    public_gpg_keys = [
        packet for packet in data.packets()
        if type(packet) == pgpdump.packet.PublicKeyPacket
    ]
    if len(public_gpg_keys) != 1:
        raise (Exception(
            "Found {} gpg public keys, require exactly 1, aborting.".format(
                len(public_gpg_keys))))

    return public_gpg_keys[0].modulus
예제 #6
0
def change_passphrase(keydata,
                      old_pass,
                      new_pass='',
                      fast=False,
                      decoding_charset='utf-8'):
    """
    Accepts a PGP key (armored or binary) and attempt to change the
    passphrase of any secret keys within.

    If new_pass is false (blank or None), the output will be an
    unprotected key. If fast is True, the new passphrase is assumed to
    already have high entropy and we use a minimal number of iterations
    when deriving the actual encryption key.

    Returns the new key in binary form, raises an exception on error.
    """
    keydata = bytes(keydata)
    if b'-----BEGIN PGP' in keydata:
        packet_iter = pgpdump.AsciiData(keydata).packets()
    else:
        packet_iter = pgpdump.BinaryData(keydata).packets()

    try:
        # Ensure correct encoding on Python 2
        if not isinstance(old_pass, unicode):
            old_pass = old_pass.decode('utf-8')
        if not isinstance(new_pass, unicode):
            new_pass = new_pass.decode('utf-8')
    except NameError:
        pass

    output = []
    for packet in packet_iter:
        if packet.raw in (5, 7):
            packet = _unlock_secret_key(packet, old_pass, decoding_charset)
            if new_pass:
                packet = _lock_secret_key(packet, new_pass, fast)
        if packet is not None:
            output.append(packet)

    newkey = b''
    for p in output:
        newkey += _pgp_header(p.raw, len(p.data)) + p.data

    return newkey
예제 #7
0
def _get_keydata(data):
    results = []
    try:
        if "-----BEGIN" in data:
            ak = pgpdump.AsciiData(data)
        else:
            ak = pgpdump.BinaryData(data)
        packets = list(ak.packets())
    except (TypeError, IndexError, PgpdumpException):
        return []

    now = time.time()
    for m in packets:
        try:
            if isinstance(m, pgpdump.packet.PublicKeyPacket):
                size = str(
                    int(1.024 * round(len('%x' % (m.modulus or 0)) / 0.256)))
                validity = ('e' if
                            (0 < (int(m.expiration_time or 0)) < now) else '')
                results.append({
                    "fingerprint":
                    m.fingerprint,
                    "created":
                    _get_creation_time(m),
                    "validity":
                    validity,
                    "keytype_name": (m.pub_algorithm or '').split()[0],
                    "keysize":
                    size,
                    "uids": [],
                })
            if isinstance(m, pgpdump.packet.UserIDPacket) and results:
                # FIXME: This used to happen with results=[], does that imply
                #        UIDs sometimes come before the PublicKeyPacket?
                results[-1]["uids"].append({
                    "name": m.user_name,
                    "email": m.user_email
                })
        except (TypeError, AttributeError, KeyError, IndexError, NameError):
            import traceback
            traceback.print_exc()

    # This will only return keys that have UIDs
    return [k for k in results if k['uids']]
예제 #8
0
    def _get_keydata(self, data):
        results = []
        try:
            if "-----BEGIN" in data:
                ak = pgpdump.AsciiData(data)
            else:
                ak = pgpdump.BinaryData(data)
        except TypeError:
            return []

        now = time.time()
        for m in ak.packets():
            try:
                if isinstance(m, pgpdump.packet.PublicKeyPacket):
                    # FIXME m.datetime throws nasty error fails hard
                    # Issue 1115
                    size = str(
                        int(1.024 * round(len('%x' % m.modulus) / 0.256)))
                    validity = ('e' if
                                (0 <
                                 (int(m.expiration_time or 0)) < now) else '')
                    results.append({
                        "fingerprint":
                        m.fingerprint,
                        "created":
                        "1970-01-01 00:00:00",
                        "validity":
                        validity,
                        "keytype_name": (m.pub_algorithm or '').split()[0],
                        "keysize":
                        size,
                        "uids": [],
                    })
                if isinstance(m, pgpdump.packet.UserIDPacket):
                    results[-1]["uids"].append({
                        "name": m.user_name,
                        "email": m.user_email
                    })
            except (AttributeError, KeyError, IndexError, NameError):
                import traceback
                traceback.print_exc()

        return results
예제 #9
0
    def eval(self, value, request):
        if '--' not in value:
            # best way i found to ignore unchanged fields.
            return IgnoreValue()
        try:
            data = pgpdump.AsciiData(bytes(value, 'utf-8'))
        except binascii.Error:
            raise ValidationError(_('Invalid PGP key'))

        packets = list(data.packets())
        if not packets:
            return IgnoreValue()

        packet = packets[0]
        if not packet:
            raise ValidationError(_('Invalid PGP key (format)'))
        if self.require and not isinstance(packet, self.require):
            raise ValidationError(_('Invalid PGP key (type)'))
        
        return data.data
예제 #10
0
    def scan(self, data, file, options, expire_at):
        self.event['total'] = {
            'public_keys': 0,
            'public_key_encrypted_session_keys': 0,
            'signatures': 0,
            'trusts': 0,
            'user_attributes': 0,
            'user_ids': 0,
        }

        self.event.setdefault('public_keys', [])
        self.event.setdefault('public_key_encrypted_session_keys', [])
        self.event.setdefault('signatures', [])
        self.event.setdefault('trusts', [])
        self.event.setdefault('user_attributes', [])
        self.event.setdefault('user_ids', [])

        try:
            data = pgpdump.AsciiData(data)
            for packet in data.packets():
                if isinstance(packet, PublicKeyPacket):
                    self.event['total']['public_keys'] += 1
                    public_key_entry = {
                        'key_id':
                        getattr(packet, 'key_id', None),
                        'pubkey_version':
                        getattr(packet, 'pubkey_version', None),
                        'fingerprint':
                        getattr(packet, 'fingerprint', None),
                        'pub_algorithm_type':
                        getattr(packet, 'pub_algorithm_type', None),
                        'key_value':
                        getattr(packet, 'key_value', None),
                    }

                    creation_time = getattr(packet, 'creation_time', None)
                    if creation_time is not None:
                        public_key_entry[
                            'creation_time'] = creation_time.isoformat()
                    expiration_time = getattr(packet, 'expiration_time', None)
                    if expiration_time is not None:
                        public_key_entry[
                            'expiration_time'] = expiration_time.isoformat()

                    if public_key_entry not in self.event['public_keys']:
                        self.event['public_keys'].append(public_key_entry)

                elif isinstance(packet, PublicKeyEncryptedSessionKeyPacket):
                    self.event['total'][
                        'public_key_encrypted_session_keys'] += 1
                    public_key_encrypted_session_key_entry = {
                        'session_key_version':
                        getattr(packet, 'session_key_version', None),
                        'key_id':
                        getattr(packet, 'key_id', None),
                        'pub_algorithm':
                        getattr(packet, 'pub_algorithm', None),
                    }

                    if public_key_encrypted_session_key_entry not in self.event[
                            'public_key_encrypted_session_keys']:
                        self.event['public_key_encrypted_session_keys'].append(
                            public_key_encrypted_session_key_entry)

                elif isinstance(packet, SignaturePacket):
                    self.event['total']['signatures'] += 1
                    signature_packet_entry = {
                        'key_id': getattr(packet, 'key_id', None),
                        'sig_version': getattr(packet, 'sig_version', None),
                        'sig_type': getattr(packet, 'sig_type', None),
                        'hash_algorithm': getattr(packet, 'hash_algorithm',
                                                  None),
                        'pub_algorithm': getattr(packet, 'pub_algorithm',
                                                 None),
                        'length': getattr(packet, 'length', None),
                    }
                    creation_time = getattr(packet, 'creation_time', None)
                    if creation_time is not None:
                        signature_packet_entry[
                            'creation_time'] = creation_time.isoformat()
                    expiration_time = getattr(packet, 'expiration_time', None)
                    if expiration_time is not None:
                        signature_packet_entry[
                            'expiration_time'] = expiration_time.isoformat()

                    if signature_packet_entry not in self.event['signatures']:
                        self.event['signatures'].append(signature_packet_entry)

                elif isinstance(packet, TrustPacket):
                    self.event['total']['trusts'] += 1
                    trust_entry = {
                        'trusts': getattr(packet, 'trusts', None),
                    }

                    if trust_entry not in self.event['trusts']:
                        self.event['trusts'].append(trust_entry)

                elif isinstance(packet, UserAttributePacket):
                    self.event['total']['user_attributes'] += 1
                    user_attribute_entry = {
                        'image_format': getattr(packet, 'image_format', None),
                        'image_data': getattr(packet, 'image_data', None),
                    }

                    if user_attribute_entry not in self.event[
                            'user_attributes']:
                        self.event['user_attributes'].append(
                            user_attribute_entry)

                elif isinstance(packet, UserIDPacket):
                    self.event['total']['user_ids'] += 1
                    user_id_entry = {
                        'user': getattr(packet, 'user', None),
                        'user_name': getattr(packet, 'user_name', None),
                        'user_email': getattr(packet, 'user_email', None),
                    }

                    if user_id_entry not in self.event['user_ids']:
                        self.event['user_ids'].append(user_id_entry)

        except TypeError:
            self.flags.append('type_error')
예제 #11
0
def minimal_key(keydata, user_id=None, subkey_id=None, binary_out=False):
    """
    Accepts a PGP key (armored or binary) and returns a minimal PGP key
    containing exactly five packets (base64 or binary) defining a
    primary key, a single user id with one self-signature, and a 
    single encryption subkey with one self-signature. Such a five packet
    key MUST be used in Autocrypt headers (Level 1 Spec section 2.1.1). 
    The unrevoked user id with newest unexpired self-signature and the
    unrevoked encryption-capable subkey with newest unexpired
    self-signature are selected from the input key.
    If user_id is provided, a user id containing that string will be 
    selected if there is one, otherwise any user id will be accepted.
    If subkey_id is specified, only a subkey with that id will be selected.
    
    Along with the new key, the selected user id and subkey id are returned.
    Returns None if there is a failure.
    
    """
    def _get_int4(data, offset):
        '''Pull four bytes from data at offset and return as an integer.'''
        return ((data[offset] << 24) + (data[offset + 1] << 16) +
                (data[offset + 2] << 8) + data[offset + 3])

    def _exp_time(creation_time, exp_time_subpacket_data):

        life_s = _get_int4(exp_time_subpacket_data, 0)
        if not life_s:
            return 0
        return packet.creation_time + datetime.timedelta(seconds=life_s)

    def _pgp_header(type, body_length):

        if body_length < 192:
            return bytearray([type + 0xC0, body_length])
        elif body_length < 8384:
            return bytearray([
                type + 0xC0, (body_length - 192) // 256 + 192,
                (body_length - 192) % 256
            ])
        else:
            return bytearray([
                type + 0xC0, 255, body_length // (1 << 24),
                body_length // (1 << 16) % 256, body_length // 1 << 8 % 256,
                body_length % 256
            ])

    pri_key = None
    u_id = None
    u_id_sig = None
    u_id_match = False
    s_key = None
    s_key_sig = None
    now = datetime.datetime.utcfromtimestamp(time.time())

    if '-----BEGIN PGP PUBLIC KEY BLOCK-----' in keydata:
        packet_iter = pgpdump.AsciiData(keydata).packets()
    else:
        packet_iter = pgpdump.BinaryData(keydata).packets()

    try:
        packet = next(packet_iter)
    except:
        packet = None

    while packet:

        if packet.raw == 6 and pri_key:  # Primary key must be the first
            break  # and only the first packet.
        elif packet.raw != 6 and not pri_key:
            break

        elif packet.raw == 6:  # Primary Public-Key Packet
            pri_key = packet

        elif packet.raw == 13:  # User ID Packet
            u_id_try = packet
            u_id_sig_try = None
            u_id_try_match = not user_id or user_id in u_id_try.user
            #**FIXME Autocrypt spec 5.1 requires E-mail address canonicalization

            # Accept a nonmatching u_id IFF no other u_id matches.
            if u_id_match and not u_id_try_match:
                u_id_try = None

            for packet in packet_iter:
                if packet.raw != 2:  # Signature Packet
                    break
                elif not u_id_try:
                    continue
                    # User ID certification
                elif packet.raw_sig_type in (0x10, 0x11, 0x12, 0x13, 0x1F):
                    if (packet.key_id in pri_key.fingerprint
                            and (not packet.expiration_time
                                 or packet.expiration_time > now) and
                        (not u_id_sig_try or
                         u_id_sig_try.creation_time < packet.creation_time)):
                        u_id_sig_try = packet
                        # Certification revocation
                elif packet.raw_sig_type == 0x30:
                    if packet.key_id in pri_key.fingerprint:
                        u_id_try = None
                        u_id_sig_try = None

            # Select unrevoked user id with newest unexpired self-signature
            if u_id_try and u_id_sig_try and (
                    not u_id or not u_id_sig
                    or u_id_try_match and not u_id_match
                    or u_id_sig_try.creation_time >= u_id_sig.creation_time):
                u_id = u_id_try
                u_id_sig = u_id_sig_try
                u_id_match = u_id_try_match
            continue  # Skip next(packet_iter) - for has done it.

        elif packet.raw == 14:  # Public-Subkey Packet
            s_key_try = packet
            s_key_sig_try = None

            # Honour a request for specific subkey and check for expiry.
            if (subkey_id and not subkey_id in s_key_try.fingerprint
                    or s_key_try.expiration_time
                    and s_key_try.expiration_time < now):
                s_key_try = None

            for packet in packet_iter:
                if packet.raw != 2:  # Signature Packet
                    break
                elif not s_key_try:
                    continue
                    # Subkey Binding Signature
                elif packet.raw_sig_type == 0x18:
                    packet.key_expire_time = None
                    if (packet.key_id in pri_key.fingerprint
                            and not packet.expiration_time
                            or packet.expiration_time >= now):
                        can_encrypt = True  # Assume encrypt if no flags.
                        for subpacket in packet.subpackets:
                            if subpacket.subtype == 9:  # Key expiration
                                # pgpdump should provide this!!
                                packet.key_expire_time = _exp_time(
                                    packet.creation_time, subpacket.data)
                            elif subpacket.subtype == 27:  # Key flags
                                can_encrypt |= subpacket.data[0] & 0x0C
                        if can_encrypt and (not packet.key_expire_time
                                            or packet.key_expire_time >= now):
                            s_key_sig_try = packet
                            # Subkey revocation signature
                elif packet.raw_sig_type == 0x28:
                    if packet.key_id in pri_key.fingerprint:
                        s_key_try = None
                        s_key_sig_try = None

            # Select unrevoked encryption-capable subkey with newest
            # unexpired self-signature (ignores newness of key itself).
            if s_key_try and s_key_sig_try and (
                    not s_key_sig
                    or s_key_sig_try.creation_time >= s_key_sig.creation_time):
                s_key = s_key_try
                s_key_sig = s_key_sig_try
            continue  # Skip next(packet_iter) - for has done it.

        try:
            packet = next(packet_iter)
        except:
            packet = None

    if not (pri_key and u_id and u_id_sig and s_key and s_key_sig):
        return '', None, None

    newkey = (_pgp_header(pri_key.raw, len(pri_key.data)) + pri_key.data +
              _pgp_header(u_id.raw, len(u_id.data)) + u_id.data +
              _pgp_header(u_id_sig.raw, len(u_id_sig.data)) + u_id_sig.data +
              _pgp_header(s_key.raw, len(s_key.data)) + s_key.data +
              _pgp_header(s_key_sig.raw, len(s_key_sig.data)) + s_key_sig.data)

    if not binary_out:
        newkey = base64.b64encode(newkey)

    return newkey, u_id.user, s_key.key_id
예제 #12
0
    def post_save(self, sender, instance, created, **kwargs):
        if created:
            data = instance.file.read()
            pgp = None
            try:
                pgp = pgpdump.AsciiData(data)
            except PgpdumpException:
                pgp = pgpdump.BinaryData(data)
            instance.file.save(instance.file.name, ContentFile(pgp.data))
            crc = crc24(pgp.data)
            crc_bin = crc.to_bytes(3, "big")
            instance.crc24 = base64.b64encode(crc_bin).decode("utf-8")
            instance.save()

            # parse packets
            index = 0
            last_pubkey = None
            last_userid = None
            for packet in pgp.packets():
                index += 1
                if (not isinstance(packet, PublicKeyPacket)
                        and not isinstance(packet, UserIDPacket)
                        and not isinstance(packet, SignaturePacket)):
                    continue
                if isinstance(packet, PublicKeyPacket):
                    is_sub = isinstance(packet, PublicSubkeyPacket)
                    creation_time = make_aware(packet.creation_time, utc)
                    expir = None
                    if packet.expiration_time is not None:
                        expir = make_aware(packet.expiration_time, utc)
                    algo = packet.raw_pub_algorithm
                    bits = 0
                    if algo in (1, 2, 3):
                        bits = len(bin(packet.modulus)[2:])
                    elif algo == 17:
                        bits = len(bin(packet.prime)[2:])
                    elif algo in (16, 20):
                        bits = len(bin(packet.prime)[2:])
                    fingerprint = packet.fingerprint.lower().decode('utf-8')
                    keyid = packet.key_id.lower().decode('utf-8')
                    last_pubkey = PGPPublicKeyModel.objects.create(
                        index=index,
                        key=instance,
                        is_sub=is_sub,
                        creation_time=creation_time,
                        expiration_time=expir,
                        algorithm=algo,
                        bits=bits,
                        fingerprint=fingerprint,
                        keyid=keyid)
                elif isinstance(packet, UserIDPacket):
                    userid = packet.data.decode("utf-8")
                    last_userid = PGPUserIDModel.objects.create(index=index,
                                                                key=instance,
                                                                userid=userid)
                elif isinstance(packet, SignaturePacket) and last_userid:
                    creation_time = make_aware(packet.creation_time, utc)
                    expir = None
                    if packet.expiration_time is not None:
                        expir = make_aware(packet.expiration_time, utc)
                    keyid = packet.key_id.lower().decode('utf-8')
                    PGPSignatureModel.objects.create(
                        index=index,
                        key=instance,
                        pkey=last_pubkey,
                        userid=last_userid,
                        type=packet.raw_sig_type,
                        pka=packet.raw_pub_algorithm,
                        hash=packet.raw_hash_algorithm,
                        creation_time=creation_time,
                        expiration_time=expir,
                        keyid=keyid)
예제 #13
0
def get_keyinfo(data, autocrypt_header=None,
                key_info_class=KeyInfo, key_uid_class=KeyUID,
                key_source=None):
    """
    This method will parse a stream of OpenPGP packets into a list of KeyInfo
    objects.

    Note: Signatures are not validated, this code only parses the data.
    """
    try:
        if "-----BEGIN" in data:
            ak = pgpdump.AsciiData(data)
        else:
            ak = pgpdump.BinaryData(data)
        packets = list(ak.packets())
    except (TypeError, IndexError, PgpdumpException):
        traceback.print_exc()
        return []

    def _unixtime(packet, seconds=0, days=0):
        return (packet.raw_creation_time
                + (days or 0) * 24 * 3600
                + (seconds or 0))

    results = []
    last_uid = key_uid_class()  # Dummy
    last_key = key_info_class()  # Dummy
    last_pubkeypacket = None
    main_key_id = None
    for m in packets:
        try:
            if isinstance(m, pgpdump.packet.PublicKeyPacket):
                size = str(int(1.024 *
                               round(len('%x' % (m.modulus or 0)) / 0.256)))
                last_pubkeypacket = m
                last_key = key_info_class(
                    key_source=key_source,
                    fingerprint=m.fingerprint,
                    keytype_name=m.pub_algorithm or '',
                    keytype_code=m.raw_pub_algorithm,
                    keysize=size)
                if isinstance(m, pgpdump.packet.PublicSubkeyPacket):
                    last_key.is_subkey = True
                    results[-1].subkeys.append(last_key)
                else:
                    main_key_id = m.key_id
                    results.append(last_key)

                # Older pgpdumps may fail here and cause traceback noise, but
                # the loop will limp onwards.
                last_key.created = _unixtime(m)
                if m.raw_days_valid > 0:
                    last_key.expires = _unixtime(m, days=m.raw_days_valid)
                    if last_key.expires == last_key.created:
                        last_key.expires = 0

            elif isinstance(m, pgpdump.packet.UserIDPacket) and results:
                last_uid = key_uid_class(name=m.user_name, email=m.user_email)
                last_key.uids.append(last_uid)

            elif isinstance(m, pgpdump.packet.SignaturePacket) and results:
                # Note: We don't actually check the signature; we trust
                #       GnuPG will if we decide to use this key.
                if m.key_id == main_key_id:
                    for s in m.subpackets:
                        if s.subtype == 9:
                            exp = _unixtime(last_pubkeypacket, seconds=get_int4(s.data, 0))
                            last_key.expires = max(last_key.expires, exp)
                        elif s.subtype == 27:
                            caps = set(c for c in last_key.capabilities)
                            for flag, c in ((0x01, 'c'), (0x02, 's'),
                                            (0x0C, 'e'), (0x20, 'a')):
                                if s.data[0] & flag:
                                    caps.add(c)
                            last_key.capabilities = ''.join(caps)

        except (TypeError, AttributeError, KeyError, IndexError, NameError):
            traceback.print_exc()

    autocrypt_uid = None
    if autocrypt_header:
        # The autocrypt spec tells us that the visible addr= attribute
        # overrides whatever is on the key itself, so we synthesize a
        # fake UID here so the info is correct in an Autocrypt context.
        autocrypt_uid = key_uid_class(
            email=autocrypt_header['addr'],
            comment='Autocrypt')

    now = time.time()
    for keyinfo in results:
        keyinfo.synthesize_validity(now=now)
        keyinfo.add_subkey_capabilities(now=now)
        keyinfo.recalculate_expiration(now=now)
        if autocrypt_uid is not None:
            keyinfo.ensure_autocrypt_uid(autocrypt_uid)

    return results
예제 #14
0
    def _return_rsa_key_from_pgp(self, pgp_key, secret):
        """
        Accepts pgp_key bytes, process it to pgpdump packets, which is a Generator class with following
        consisting objects:

        @developer: tnanoba

            SecretKeyPacket object
            UserIDPacket object
            SignaturePacket object

            SecretKeyPacket object dict structure:

                {
                    'prime_p': '...', (p)
                    'prime_q': '...', (q)
                    'exponent': '...', (e)
                    'modulus': '...', (p * q = n)
                    'exponent_d': '...', (d)
                    'data': '...',
                    'raw_creation_time': '...',
                    's2k_type': '...',
                    'checksum': '...',
                    'pubkey_version': '...',
                    'exponent_x': '...',
                    's2k_id': '...',
                    's2k_cipher': '...',
                    'new': '...',
                    'creation_time': '...',
                    'fingerprint': '...',
                    'multiplicative_inverse': '...',
                    'raw': '...',
                    'prime': '...',
                    'length': '...',
                    'group_gen': '...',
                    'pub_algorithm_type': '...',
                    'raw_days_valid': '...',
                    'name': '...',
                    'key_id': '...',
                    's2k_hash': '...',
                    'raw_pub_algorithm': '...',
                    'expiration_time': '...',
                    's2k_iv': '...',
                    'group_order': '...'
                }

        :param pgp_key: bytes
        :param secret: bool
        :return: object
        """
        try:
            packets = list(pgpdump.AsciiData(pgp_key).packets())

            if secret:
                # Returns RSA private key instance
                return self.compute_rsa_private_key(
                    packets[0].__dict__['prime_p'],
                    packets[0].__dict__['prime_q'],
                    packets[0].__dict__['exponent'],
                    packets[0].__dict__['modulus'],
                    packets[0].__dict__['exponent_d'])
            else:
                # Returns RSA public key instance
                return self.compute_rsa_public_key(
                    packets[0].__dict__['exponent'],
                    packets[0].__dict__['modulus'],
                )
        except Exception as ERROR:
            self.logger.error(ERROR)
예제 #15
0
def load_key(key_asc):
    data = pgpdump.AsciiData(key_asc)
    entities = []
    pubkey = None
    curkey = None
    curuid = None
    subkey_latest_selfsig = datetime.datetime.utcfromtimestamp(0)
    pubkey_latest_selfsig = datetime.datetime.utcfromtimestamp(0)
    uid_latest_selfsig = datetime.datetime.utcfromtimestamp(0)

    for packet in data.packets():
        if isinstance(packet,
                      pgpdump.packet.PublicKeyPacket) and not isinstance(
                          packet, pgpdump.packet.SecretKeyPacket):
            if type(packet) == pgpdump.packet.PublicKeyPacket:
                pubkey_latest_selfsig = datetime.datetime.utcfromtimestamp(0)
                pubkey = models.PublicKey()
                curkey = pubkey
                # Ugh, BlobProperty wants str, not bytearray
                pubkey.key_data = str(data.data)
            else:
                subkey_latest_selfsig = datetime.datetime.utcfromtimestamp(0)
                curkey = models.PublicSubkey()
            entities.append(curkey)

            curkey.reversed_fingerprint = codecs.decode(
                packet.fingerprint.decode('ascii'), 'hex')[::-1]
            if type(packet) == pgpdump.packet.PublicKeyPacket:
                curkey.key = ndb.Key(models.PublicKey,
                                     curkey.stringid,
                                     namespace='hkp')
            else:
                curkey.key = ndb.Key(models.PublicSubkey,
                                     curkey.stringid,
                                     parent=pubkey.key,
                                     namespace='hkp')
                pubkey.subkeys.append(curkey.key)

            curkey.creation_time = packet.creation_time
            curkey.expiration_time = packet.expiration_time
            curkey.algorithm_type = packet.pub_algorithm_type
            curkey.bitlen = packet.modulus_bitlen
        elif isinstance(packet, pgpdump.packet.UserIDPacket):
            uid_latest_selfsig = datetime.datetime.utcfromtimestamp(0)
            curuid = models.Uid()
            entities.append(curuid)
            curuid.key = ndb.Key(models.Uid,
                                 packet.user,
                                 parent=pubkey.key,
                                 namespace='hkp')
            pubkey.uids.append(curuid.key)
            curuid.uid = uni_utils.compatibility_casefold(packet.user)
        elif isinstance(packet, pgpdump.packet.SignaturePacket):
            # self-sig
            if packet.key_id == pubkey.keyid:
                # At this point only interested in UID, subkey, or sig directly on key
                # TODO should record revocation as well
                if packet.raw_sig_type in (0x10, 0x11, 0x12, 0x13, 0x18, 0x1F):
                    # From RFC4880:
                    #  Subpackets that appear in a certification self-signature
                    #  apply to the user name, and subpackets that appear in the subkey
                    #  self-signature apply to the subkey.  Lastly, subpackets on the
                    #  direct-key signature apply to the entire key.
                    #
                    # NOTE while the certification subpackets should apply to the user name,
                    # not the entire key, gpg seems to put properties of the public key in the
                    # certification signature(s).  So, no else here...
                    if packet.raw_sig_type >= 0x10 and packet.raw_sig_type <= 0x13 and uid_latest_selfsig < packet.creation_time:
                        uid_latest_selfsig = packet.creation_time
                        curuid.creation_time = packet.creation_time
                        curuid.expiration_time = packet.expiration_time
                    if (packet.raw_sig_type == 0x18
                            and subkey_latest_selfsig < packet.creation_time
                        ) or (packet.raw_sig_type != 0x18 and
                              pubkey_latest_selfsig < packet.creation_time):
                        # Should modify pubkey even if the direct-key sig packet happens after subkeys
                        modkey = curkey if packet.raw_sig_type == 0x18 else pubkey
                        for subpack in packet.subpackets:
                            if subpack.subtype == 9:  # Key Expiration Time
                                modkey.expiration_time = modkey.creation_time + datetime.timedelta(
                                    seconds=pgpdump.utils.get_int4(
                                        subpack.data, 0))
                            elif subpack.subtype == 27:  # Key Flags
                                modkey.flags = subpack.data[0]
                            elif subpack.subtype == 23:  # Key Server Preferences (do we need these?)
                                pass

    ndb.put_multi(entities)
예제 #16
0

class PublicKey(KeyBase):
    def __init__(self):
        super(PublicKey, self).__init__()
        self.uids = []
        self.subkeys = []
        self.key_data = bytearray()

    @property
    def asciiarmored(self):
        return utils.asciiarmor('PUBLIC KEY BLOCK', self.key_data)


with open('mykey.asc', 'rb') as infile:
    data = pgpdump.AsciiData(infile.read())

pubkeys = []
pubkey = None
curkey = None
curuid = None
subkey_latest_selfsig = datetime.datetime.utcfromtimestamp(0)
pubkey_latest_selfsig = datetime.datetime.utcfromtimestamp(0)
uid_latest_selfsig = datetime.datetime.utcfromtimestamp(0)

for packet in data.packets():
    print(str(type(packet)))
    pp.pprint(packet.__dict__)
    if isinstance(packet, pgpdump.packet.PublicKeyPacket) and not isinstance(
            packet, pgpdump.packet.SecretKeyPacket):
        if type(packet) == pgpdump.packet.PublicKeyPacket:
예제 #17
0
    def scan(self, file_object, options):
        self.metadata["total"] = {"publicKeys": 0,
                                  "publicKeyEncryptedSessionKeys": 0,
                                  "signatures": 0,
                                  "trusts": 0,
                                  "userAttributes": 0,
                                  "userIds": 0}

        self.metadata.setdefault("publicKeys", [])
        self.metadata.setdefault("publicKeyEncryptedSessionKeys", [])
        self.metadata.setdefault("signatures", [])
        self.metadata.setdefault("trusts", [])
        self.metadata.setdefault("userAttributes", [])
        self.metadata.setdefault("userIds", [])

        try:
            data = pgpdump.AsciiData(file_object.data)
            for packet in data.packets():
                if isinstance(packet, PublicKeyPacket):
                    self.metadata["total"]["publicKeys"] += 1
                    public_key_entry = {}
                    key_id = getattr(packet, "key_id", None)
                    if key_id is not None:
                        public_key_entry["keyId"] = key_id
                    pubkey_version = getattr(packet, "pubkey_version", None)
                    if pubkey_version is not None:
                        public_key_entry["pubkeyVersion"] = pubkey_version
                    fingerprint = getattr(packet, "fingerprint", None)
                    if fingerprint is not None:
                        public_key_entry["fingerprint"] = fingerprint
                    pub_algorithm_type = getattr(packet, "pub_algorithm_type", None)
                    if pub_algorithm_type is not None:
                        public_key_entry["pubAlgorithmType"] = pub_algorithm_type
                    key_value = getattr(packet, "key_value", None)
                    if key_value is not None:
                        public_key_entry["keyValue"] = key_value
                    creation_time = getattr(packet, "creation_time", None)
                    if creation_time is not None:
                        public_key_entry["creationTime"] = creation_time.isoformat(timespec="seconds")
                    expiration_time = getattr(packet, "expiration_time", None)
                    if expiration_time is not None:
                        public_key_entry["expirationTime"] = expiration_time.isoformat(timespec="seconds")

                    if (public_key_entry and
                        public_key_entry not in self.metadata["publicKeys"]):
                        self.metadata["publicKeys"].append(public_key_entry)

                elif isinstance(packet, PublicKeyEncryptedSessionKeyPacket):
                    self.metadata["total"]["publicKeyEncryptedSessionKeys"] += 1
                    public_key_encrypted_session_key_entry = {}
                    session_key_version = getattr(packet, "session_key_version", None)
                    if session_key_version is not None:
                        public_key_encrypted_session_key_entry["sessionKeyVersion"] = session_key_version
                    key_id = getattr(packet, "key_id", None)
                    if key_id is not None:
                        public_key_encrypted_session_key_entry["keyId"] = key_id
                    pub_algorithm = getattr(packet, "pub_algorithm", None)
                    if pub_algorithm is not None:
                        public_key_encrypted_session_key_entry["pubAlgorithm"] = pub_algorithm

                    if (public_key_encrypted_session_key_entry and
                        public_key_encrypted_session_key_entry not in self.metadata["publicKeyEncryptedSessionKeys"]):
                        self.metadata["publicKeyEncryptedSessionKeys"].append(public_key_encrypted_session_key_entry)

                elif isinstance(packet, SignaturePacket):
                    self.metadata["total"]["signatures"] += 1
                    signature_packet_entry = {}
                    key_id = getattr(packet, "key_id", None)
                    if key_id is not None:
                        signature_packet_entry["keyId"] = key_id
                    sig_version = getattr(packet, "sig_version", None)
                    if sig_version is not None:
                        signature_packet_entry["sigVersion"] = sig_version
                    sig_type = getattr(packet, "sig_type", None)
                    if sig_type is not None:
                        signature_packet_entry["sigType"] = sig_type
                    hash_algorithm = getattr(packet, "hash_algorithm", None)
                    if hash_algorithm is not None:
                        signature_packet_entry["hashAlgorithm"] = hash_algorithm
                    pub_algorithm = getattr(packet, "pub_algorithm", None)
                    if pub_algorithm is not None:
                        signature_packet_entry["pubAlgorithm"] = pub_algorithm
                    creation_time = getattr(packet, "creation_time", None)
                    if creation_time is not None:
                        signature_packet_entry["creationTime"] = creation_time.isoformat(timespec="seconds")
                    expiration_time = getattr(packet, "expiration_time", None)
                    if expiration_time is not None:
                        signature_packet_entry["expirationTime"] = expiration_time.isoformat(timespec="seconds")
                    length = getattr(packet, "length", None)
                    if length is not None:
                        signature_packet_entry["length"] = length

                    if (signature_packet_entry and
                        signature_packet_entry not in self.metadata["signatures"]):
                        self.metadata["signatures"].append(signature_packet_entry)

                elif isinstance(packet, TrustPacket):
                    self.metadata["total"]["trusts"] += 1
                    trust_entry = {}
                    trusts = getattr(packet, "trusts", None)
                    if trusts is not None:
                        trust_entry["trusts"] = trusts

                    if (trust_entry and
                        trust_entry not in self.metadata["trusts"]):
                        self.metadata["trusts"].append(trust_entry)

                elif isinstance(packet, UserAttributePacket):
                    self.metadata["total"]["userAttributes"] += 1
                    user_attribute_entry = {}
                    image_format = getattr(packet, "image_format", None)
                    if image_format is not None:
                        user_attribute_entry["imageFormat"] = image_format
                    image_data = getattr(packet, "image_data", None)
                    if image_data is not None:
                        user_attribute_entry["imageData"] = image_data

                    if (user_attribute_entry and
                        user_attribute_entry not in self.metadata["userAttributes"]):
                        self.metadata["userAttributes"].append(user_attribute_entry)

                elif isinstance(packet, UserIDPacket):
                    self.metadata["total"]["userIds"] += 1
                    user_id_entry = {}
                    user = getattr(packet, "user", None)
                    if user is not None:
                        user_id_entry["user"] = user
                    user_name = getattr(packet, "user_name", None)
                    if user_name is not None:
                        user_id_entry["userName"] = user_name
                    user_email = getattr(packet, "user_email", None)
                    if user_email is not None:
                        user_id_entry["userEmail"] = user_email

                    if (user_id_entry and
                        user_id_entry not in self.metadata["userIds"]):
                        self.metadata["userIds"].append(user_id_entry)

        except TypeError:
            file_object.flags.append(f"{self.scanner_name}::type_error")
예제 #18
0
def get_keydata(data, include_subkeys=False, autocrypt_header=None):
    results = []
    try:
        if "-----BEGIN" in data:
            ak = pgpdump.AsciiData(data)
        else:
            ak = pgpdump.BinaryData(data)
        packets = list(ak.packets())
    except (TypeError, IndexError, PgpdumpException):
        return []

    if autocrypt_header:
        # The autocrypt spec tells us that the visible addr= attribute
        # overrides whatever is on the key itself, so we synthesize a
        # fake UID here so strict e-mail matches don't break Autocrypt.
        ac_uid = {'comment': 'Autocrypt', 'email': autocrypt_header['addr']}
    else:
        ac_uid = None

    now = time.time()
    for m in packets:
        try:
            if isinstance(m, pgpdump.packet.PublicKeyPacket):
                size = str(
                    int(1.024 * round(len('%x' % (m.modulus or 0)) / 0.256)))
                validity = ('e' if
                            (0 < (int(m.expiration_time or 0)) < now) else '')
                results.append({
                    "fingerprint":
                    m.fingerprint,
                    "created":
                    _get_creation_time(m),
                    "validity":
                    validity,
                    "keytype_name": (m.pub_algorithm or '').split()[0],
                    "keysize":
                    size,
                    "uids": []
                })
            if isinstance(m, pgpdump.packet.UserIDPacket) and results:
                # FIXME: This used to happen with results=[], does that imply
                #        UIDs sometimes come before the PublicKeyPacket?
                results[-1]["uids"].append({
                    "name": m.user_name,
                    "email": m.user_email
                })
        except (TypeError, AttributeError, KeyError, IndexError, NameError):
            import traceback
            traceback.print_exc()

    if not include_subkeys:
        # This will only return keys that have UIDs
        results = [k for k in results if k['uids']]

    # Ensure that all the keys we're returning have the Autocrypt UID,
    # if they have UIDs at all.
    if ac_uid is not None:
        for k in results:
            found = 0
            for u in k['uids']:
                if u['email'] == ac_uid['email']:
                    u['comment'] = u.get('comment', '') + '(Autocrypt)'
                    found += 1
            if k['uids'] and not found:
                k['uids'] += [ac_uid]

    return results