aboutsummaryrefslogtreecommitdiffstats
path: root/tmk_core/common/backlight.c
blob: c9e8fd3fd2ddbe3fce3afd0096f13f3cfab1f2c2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/*
Copyright 2013 Mathias Andersson <wraul@dbox.se>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "backlight.h"
#include "eeconfig.h"
#include "debug.h"

backlight_config_t backlight_config;

void backlight_init(void)
{
    /* check signature */
    if (!eeconfig_is_enabled()) {
        eeconfig_init();
    }
    backlight_config.raw = eeconfig_read_backlight();
    backlight_set(backlight_config.enable ? backlight_config.level : 0);
}

void backlight_increase(void)
{
    if(backlight_config.level < BACKLIGHT_LEVELS)
    {
        backlight_config.level++;
        backlight_config.enable = 1;
        eeconfig_update_backlight(backlight_config.raw);
    }
    dprintf("backlight increase: %u\n", backlight_config.level);
    backlight_set(backlight_config.level);
}

void backlight_decrease(void)
{
    if(backlight_config.level > 0)
    {
        backlight_config.level--;
        backlight_config.enable = !!backlight_config.level;
        eeconfig_update_backlight(backlight_config.raw);
    }
    dprintf("backlight decrease: %u\n", backlight_config.level);
    backlight_set(backlight_config.level);
}

void backlight_toggle(void)
{
    backlight_config.enable ^= 1;
    eeconfig_update_backlight(backlight_config.raw);
    dprintf("backlight toggle: %u\n", backlight_config.enable);
    backlight_set(backlight_config.enable ? backlight_config.level : 0);
}

void backlight_step(void)
{
    backlight_config.level++;
    if(backlight_config.level > BACKLIGHT_LEVELS)
    {
        backlight_config.level = 0;
    }
    backlight_config.enable = !!backlight_config.level;
    eeconfig_update_backlight(backlight_config.raw);
    dprintf("backlight step: %u\n", backlight_config.level);
    backlight_set(backlight_config.level);
}

void backlight_level(uint8_t level)
{
    backlight_config.level ^= level;
    backlight_config.enable = !!backlight_config.level;
    eeconfig_update_backlight(backlight_config.raw);
    backlight_set(backlight_config.level);
}

uint8_t get_backlight_level(void)
{
    return backlight_config.level;
}
*/ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
/*
 * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
 * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.sufficientlysecure.keychain.pgp;

import org.spongycastle.bcpg.ECPublicBCPGKey;
import org.spongycastle.bcpg.SignatureSubpacketTags;
import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPSignature;
import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Utf8Util;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Iterator;

public class UncachedPublicKey {
    protected final PGPPublicKey mPublicKey;
    private Integer mCacheUsage = null;

    public UncachedPublicKey(PGPPublicKey key) {
        mPublicKey = key;
    }

    public long getKeyId() {
        return mPublicKey.getKeyID();
    }

    /** The revocation signature is NOT checked here, so this may be false! */
    public boolean isRevoked() {
        return mPublicKey.getSignaturesOfType(isMasterKey()
                ? PGPSignature.KEY_REVOCATION
                : PGPSignature.SUBKEY_REVOCATION).hasNext();
    }

    public Date getCreationTime() {
        return mPublicKey.getCreationTime();
    }

    public boolean isExpired() {
        Date creationDate = mPublicKey.getCreationTime();
        Date expiryDate = mPublicKey.getValidSeconds() > 0
                ? new Date(creationDate.getTime() + mPublicKey.getValidSeconds() * 1000) : null;

        Date now = new Date();
        return creationDate.after(now) || (expiryDate != null && expiryDate.before(now));
    }

    public boolean isMasterKey() {
        return mPublicKey.isMasterKey();
    }

    public int getAlgorithm() {
        return mPublicKey.getAlgorithm();
    }

    public Integer getBitStrength() {
        if (isEC()) {
            return null;
        }
        return mPublicKey.getBitStrength();
    }

    public String getCurveOid() {
        if ( ! isEC()) {
            return null;
        }
        if ( ! (mPublicKey.getPublicKeyPacket().getKey() instanceof ECPublicBCPGKey)) {
            return null;
        }
        return ((ECPublicBCPGKey) mPublicKey.getPublicKeyPacket().getKey()).getCurveOID().getId();
    }

    /** Returns the primary user id, as indicated by the public key's self certificates.
     *
     * This is an expensive operation, since potentially a lot of certificates (and revocations)
     * have to be checked, and even then the result is NOT guaranteed to be constant through a
     * canonicalization operation.
     *
     * Returns null if there is no primary user id (as indicated by certificates)
     *
     */
    public String getPrimaryUserId() {
        byte[] found = null;
        PGPSignature foundSig = null;
        // noinspection unchecked
        for (byte[] rawUserId : new IterableIterator<byte[]>(mPublicKey.getRawUserIDs())) {
            PGPSignature revocation = null;

            @SuppressWarnings("unchecked")
            Iterator<PGPSignature> signaturesIt = mPublicKey.getSignaturesForID(rawUserId);
            // no signatures for this User ID
            if (signaturesIt == null) {
                continue;
            }

            for (PGPSignature sig : new IterableIterator<>(signaturesIt)) {
                try {

                    // if this is a revocation, this is not the user id
                    if (sig.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION) {
                        // make sure it's actually valid
                        sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider(
                                Constants.BOUNCY_CASTLE_PROVIDER_NAME), mPublicKey);
                        if (!sig.verifyCertification(rawUserId, mPublicKey)) {
                            continue;
                        }
                        if (found != null && Arrays.equals(found, rawUserId)) {
                            found = null;
                        }
                        revocation = sig;
                        // this revocation may still be overridden by a newer cert
                        continue;
                    }

                    if (sig.getHashedSubPackets() != null && sig.getHashedSubPackets().isPrimaryUserID()) {
                        if (foundSig != null && sig.getCreationTime().before(foundSig.getCreationTime())) {
                            continue;
                        }
                        // ignore if there is a newer revocation for this user id
                        if (revocation != null && sig.getCreationTime().before(revocation.getCreationTime())) {
                            continue;
                        }
                        // make sure it's actually valid
                        sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider(
                                Constants.BOUNCY_CASTLE_PROVIDER_NAME), mPublicKey);
                        if (sig.verifyCertification(rawUserId, mPublicKey)) {
                            found = rawUserId;
                            foundSig = sig;
                            // this one can't be relevant anymore at this point
                            revocation = null;
                        }
                    }

                } catch (Exception e) {
                    // nothing bad happens, the key is just not considered the primary key id
                }
            }
        }
        if (found != null) {
            return Utf8Util.fromUTF8ByteArrayReplaceBadEncoding(found);
        } else {
            return null;
        }
    }

    /**
     * Returns primary user id if existing. If not, return first encountered user id. If there
     * is no user id, return null (this can only happen for not yet canonicalized keys during import)
     */
    public String getPrimaryUserIdWithFallback()  {
        String userId = getPrimaryUserId();
        if (userId == null) {
            Iterator<String> it = mPublicKey.getUserIDs();
            userId = it.hasNext() ? it.next() : null;
        }
        return userId;
    }

    public ArrayList<String> getUnorderedUserIds() {
        ArrayList<String> userIds = new ArrayList<>();
        for (byte[] rawUserId : new IterableIterator<byte[]>(mPublicKey.getRawUserIDs())) {
            // use our decoding method
            userIds.add(Utf8Util.fromUTF8ByteArrayReplaceBadEncoding(rawUserId));
        }
        return userIds;
    }

    public ArrayList<byte[]> getUnorderedRawUserIds() {
        ArrayList<byte[]> userIds = new ArrayList<>();
        for (byte[] userId : new IterableIterator<byte[]>(mPublicKey.getRawUserIDs())) {
            userIds.add(userId);
        }
        return userIds;
    }

    public ArrayList<WrappedUserAttribute> getUnorderedUserAttributes() {
        ArrayList<WrappedUserAttribute> userAttributes = new ArrayList<>();
        for (PGPUserAttributeSubpacketVector userAttribute :
                new IterableIterator<PGPUserAttributeSubpacketVector>(mPublicKey.getUserAttributes())) {
            userAttributes.add(new WrappedUserAttribute(userAttribute));
        }
        return userAttributes;
    }

    public boolean isElGamalEncrypt() {
        return getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT;
    }

    public boolean isDSA() {
        return getAlgorithm() == PGPPublicKey.DSA;
    }

    public boolean isEC() {
        return getAlgorithm() == PGPPublicKey.ECDH || getAlgorithm() == PGPPublicKey.ECDSA;
    }

    public byte[] getFingerprint() {
        return mPublicKey.getFingerprint();
    }

    // (It's still used in ProviderHelper at this point)
    PGPPublicKey getPublicKey() {
        return mPublicKey;
    }

    public Iterator<WrappedSignature> getSignatures() {
        final Iterator<PGPSignature> it = mPublicKey.getSignatures();
        return new Iterator<WrappedSignature>() {
            public void remove() {
                it.remove();
            }
            public WrappedSignature next() {
                return new WrappedSignature(it.next());
            }
            public boolean hasNext() {
                return it.hasNext();
            }
        };
    }

    public Iterator<WrappedSignature> getSignaturesForRawId(byte[] rawUserId) {
        final Iterator<PGPSignature> it = mPublicKey.getSignaturesForID(rawUserId);
        if (it != null) {
            return new Iterator<WrappedSignature>() {
                public void remove() {
                    it.remove();
                }
                public WrappedSignature next() {
                    return new WrappedSignature(it.next());
                }
                public boolean hasNext() {
                    return it.hasNext();
                }
            };
        } else {
            return null;
        }
    }

    public Iterator<WrappedSignature> getSignaturesForUserAttribute(WrappedUserAttribute attribute) {
        final Iterator<PGPSignature> it = mPublicKey.getSignaturesForUserAttribute(attribute.getVector());
        if (it != null) {
            return new Iterator<WrappedSignature>() {
                public void remove() {
                    it.remove();
                }
                public WrappedSignature next() {
                    return new WrappedSignature(it.next());
                }
                public boolean hasNext() {
                    return it.hasNext();
                }
            };
        } else {
            return null;
        }
    }

    /** Get all key usage flags.
     * If at least one key flag subpacket is present return these. If no
     * subpacket is present it returns null.
     *
     * Note that this method has package visiblity because it is used in test
     * cases. Certificates of UncachedPublicKey instances can NOT be assumed to
     * be verified or even by the correct key, so the result of this method
     * should never be used in other places!
     */
    @SuppressWarnings("unchecked")
    Integer getKeyUsage() {
        if (mCacheUsage == null) {
            PGPSignature mostRecentSig = null;
            for (PGPSignature sig : new IterableIterator<PGPSignature>(mPublicKey.getSignatures())) {
                if (mPublicKey.isMasterKey() && sig.getKeyID() != mPublicKey.getKeyID()) {
                    continue;
                }

                switch (sig.getSignatureType()) {
                    case PGPSignature.DEFAULT_CERTIFICATION:
                    case PGPSignature.POSITIVE_CERTIFICATION:
                    case PGPSignature.CASUAL_CERTIFICATION:
                    case PGPSignature.NO_CERTIFICATION:
                    case PGPSignature.SUBKEY_BINDING:
                        break;
                    // if this is not one of the above types, don't care
                    default:
                        continue;
                }

                // If we have no sig yet, take the first we can get
                if (mostRecentSig == null) {
                    mostRecentSig = sig;
                    continue;
                }

                // If the new sig is less recent, skip it
                if (mostRecentSig.getCreationTime().after(sig.getCreationTime())) {
                    continue;
                }

                // Otherwise, note it down as the new "most recent" one
                mostRecentSig = sig;
            }

            // Initialize to 0 as cached but empty value, if there is no sig (can't happen
            // for canonicalized keyring), or there is no KEY_FLAGS packet in the sig
            mCacheUsage = 0;
            if (mostRecentSig != null) {
                // If a mostRecentSig has been found, (cache and) return its flags
                PGPSignatureSubpacketVector hashed = mostRecentSig.getHashedSubPackets();
                if (hashed != null && hashed.getSubpacket(SignatureSubpacketTags.KEY_FLAGS) != null) {
                    mCacheUsage = hashed.getKeyFlags();
                }
            }

        }
        return mCacheUsage;
    }

}