001// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
002//
003// SPDX-License-Identifier: Apache-2.0
004
005package org.pgpainless.signature.subpackets;
006
007import org.bouncycastle.bcpg.SignatureSubpacket;
008import org.bouncycastle.bcpg.sig.EmbeddedSignature;
009import org.bouncycastle.bcpg.sig.Exportable;
010import org.bouncycastle.bcpg.sig.Features;
011import org.bouncycastle.bcpg.sig.IntendedRecipientFingerprint;
012import org.bouncycastle.bcpg.sig.KeyExpirationTime;
013import org.bouncycastle.bcpg.sig.KeyFlags;
014import org.bouncycastle.bcpg.sig.NotationData;
015import org.bouncycastle.bcpg.sig.PreferredAlgorithms;
016import org.bouncycastle.bcpg.sig.PrimaryUserID;
017import org.bouncycastle.bcpg.sig.Revocable;
018import org.bouncycastle.bcpg.sig.RevocationKey;
019import org.bouncycastle.bcpg.sig.RevocationReason;
020import org.bouncycastle.bcpg.sig.SignatureExpirationTime;
021import org.bouncycastle.bcpg.sig.SignatureTarget;
022import org.bouncycastle.bcpg.sig.SignerUserID;
023import org.bouncycastle.bcpg.sig.TrustSignature;
024import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator;
025import org.bouncycastle.openpgp.PGPSignatureSubpacketVector;
026import org.pgpainless.algorithm.Feature;
027import org.pgpainless.algorithm.HashAlgorithm;
028import org.pgpainless.algorithm.KeyFlag;
029import org.pgpainless.algorithm.PublicKeyAlgorithm;
030import org.pgpainless.key.util.RevocationAttributes;
031
032public class SignatureSubpacketsHelper {
033
034    public static SignatureSubpackets applyFrom(PGPSignatureSubpacketVector vector, SignatureSubpackets subpackets) {
035        for (SignatureSubpacket subpacket : vector.toArray()) {
036            org.pgpainless.algorithm.SignatureSubpacket type = org.pgpainless.algorithm.SignatureSubpacket.fromCode(subpacket.getType());
037            switch (type) {
038                case signatureCreationTime:
039                case issuerKeyId:
040                case issuerFingerprint:
041                    // ignore, we override this anyways
042                    break;
043                case signatureExpirationTime:
044                    SignatureExpirationTime sigExpTime = (SignatureExpirationTime) subpacket;
045                    subpackets.setSignatureExpirationTime(sigExpTime.isCritical(), sigExpTime.getTime());
046                    break;
047                case exportableCertification:
048                    Exportable exp = (Exportable) subpacket;
049                    subpackets.setExportable(exp.isCritical(), exp.isExportable());
050                    break;
051                case trustSignature:
052                    TrustSignature trustSignature = (TrustSignature) subpacket;
053                    subpackets.setTrust(trustSignature.isCritical(), trustSignature.getDepth(), trustSignature.getTrustAmount());
054                    break;
055                case revocable:
056                    Revocable rev = (Revocable) subpacket;
057                    subpackets.setRevocable(rev.isCritical(), rev.isRevocable());
058                    break;
059                case keyExpirationTime:
060                    KeyExpirationTime keyExpTime = (KeyExpirationTime) subpacket;
061                    subpackets.setKeyExpirationTime(keyExpTime.isCritical(), keyExpTime.getTime());
062                    break;
063                case preferredSymmetricAlgorithms:
064                    subpackets.setPreferredSymmetricKeyAlgorithms((PreferredAlgorithms) subpacket);
065                    break;
066                case revocationKey:
067                    RevocationKey revocationKey = (RevocationKey) subpacket;
068                    subpackets.addRevocationKey(revocationKey);
069                    break;
070                case notationData:
071                    NotationData notationData = (NotationData) subpacket;
072                    subpackets.addNotationData(notationData.isCritical(), notationData.getNotationName(), notationData.getNotationValue());
073                    break;
074                case preferredHashAlgorithms:
075                    subpackets.setPreferredHashAlgorithms((PreferredAlgorithms) subpacket);
076                    break;
077                case preferredCompressionAlgorithms:
078                    subpackets.setPreferredCompressionAlgorithms((PreferredAlgorithms) subpacket);
079                    break;
080                case primaryUserId:
081                    PrimaryUserID primaryUserID = (PrimaryUserID) subpacket;
082                    subpackets.setPrimaryUserId(primaryUserID);
083                    break;
084                case keyFlags:
085                    KeyFlags flags = (KeyFlags) subpacket;
086                    subpackets.setKeyFlags(flags.isCritical(), KeyFlag.fromBitmask(flags.getFlags()).toArray(new KeyFlag[0]));
087                    break;
088                case signerUserId:
089                    SignerUserID signerUserID = (SignerUserID) subpacket;
090                    subpackets.setSignerUserId(signerUserID.isCritical(), signerUserID.getID());
091                    break;
092                case revocationReason:
093                    RevocationReason reason = (RevocationReason) subpacket;
094                    subpackets.setRevocationReason(reason.isCritical(),
095                            RevocationAttributes.Reason.fromCode(reason.getRevocationReason()),
096                            reason.getRevocationDescription());
097                    break;
098                case features:
099                    Features f = (Features) subpacket;
100                    subpackets.setFeatures(f.isCritical(), Feature.fromBitmask(f.getData()[0]).toArray(new Feature[0]));
101                    break;
102                case signatureTarget:
103                    SignatureTarget target = (SignatureTarget) subpacket;
104                    subpackets.setSignatureTarget(target.isCritical(),
105                            PublicKeyAlgorithm.fromId(target.getPublicKeyAlgorithm()),
106                            HashAlgorithm.fromId(target.getHashAlgorithm()),
107                            target.getHashData());
108                    break;
109                case embeddedSignature:
110                    EmbeddedSignature embeddedSignature = (EmbeddedSignature) subpacket;
111                    subpackets.addEmbeddedSignature(embeddedSignature);
112                    break;
113                case intendedRecipientFingerprint:
114                    IntendedRecipientFingerprint intendedRecipientFingerprint = (IntendedRecipientFingerprint) subpacket;
115                    subpackets.addIntendedRecipientFingerprint(intendedRecipientFingerprint);
116                    break;
117
118                case regularExpression:
119                case keyServerPreferences:
120                case preferredKeyServers:
121                case policyUrl:
122                case placeholder:
123                case preferredAEADAlgorithms:
124                case attestedCertification:
125                    subpackets.addResidualSubpacket(subpacket);
126                    break;
127            }
128        }
129        return subpackets;
130    }
131
132    public static PGPSignatureSubpacketGenerator applyTo(SignatureSubpackets subpackets, PGPSignatureSubpacketGenerator generator) {
133        addSubpacket(generator, subpackets.getIssuerKeyIdSubpacket());
134        addSubpacket(generator, subpackets.getIssuerFingerprintSubpacket());
135        addSubpacket(generator, subpackets.getSignatureCreationTimeSubpacket());
136        addSubpacket(generator, subpackets.getSignatureExpirationTimeSubpacket());
137        addSubpacket(generator, subpackets.getExportableSubpacket());
138        for (NotationData notationData : subpackets.getNotationDataSubpackets()) {
139            addSubpacket(generator, notationData);
140        }
141        for (IntendedRecipientFingerprint intendedRecipientFingerprint : subpackets.getIntendedRecipientFingerprintSubpackets()) {
142            addSubpacket(generator, intendedRecipientFingerprint);
143        }
144        for (RevocationKey revocationKey : subpackets.getRevocationKeySubpackets()) {
145            addSubpacket(generator, revocationKey);
146        }
147        addSubpacket(generator, subpackets.getSignatureTargetSubpacket());
148        addSubpacket(generator, subpackets.getFeaturesSubpacket());
149        addSubpacket(generator, subpackets.getKeyFlagsSubpacket());
150        addSubpacket(generator, subpackets.getTrustSubpacket());
151        addSubpacket(generator, subpackets.getPreferredCompressionAlgorithmsSubpacket());
152        addSubpacket(generator, subpackets.getPreferredSymmetricKeyAlgorithmsSubpacket());
153        addSubpacket(generator, subpackets.getPreferredHashAlgorithmsSubpacket());
154        for (EmbeddedSignature embeddedSignature : subpackets.getEmbeddedSignatureSubpackets()) {
155            addSubpacket(generator, embeddedSignature);
156        }
157        addSubpacket(generator, subpackets.getSignerUserIdSubpacket());
158        addSubpacket(generator, subpackets.getKeyExpirationTimeSubpacket());
159        addSubpacket(generator, subpackets.getPrimaryUserIdSubpacket());
160        addSubpacket(generator, subpackets.getRevocableSubpacket());
161        addSubpacket(generator, subpackets.getRevocationReasonSubpacket());
162        for (SignatureSubpacket subpacket : subpackets.getResidualSubpackets()) {
163            addSubpacket(generator, subpacket);
164        }
165
166        return generator;
167    }
168
169    private static void addSubpacket(PGPSignatureSubpacketGenerator generator, SignatureSubpacket subpacket) {
170        if (subpacket != null) {
171            generator.addCustomSubpacket(subpacket);
172        }
173    }
174
175    public static PGPSignatureSubpacketVector toVector(SignatureSubpackets subpackets) {
176        PGPSignatureSubpacketGenerator generator = new PGPSignatureSubpacketGenerator();
177        applyTo(subpackets, generator);
178        return generator.generate();
179    }
180
181    public static PGPSignatureSubpacketVector toVector(RevocationSignatureSubpackets subpackets) {
182        PGPSignatureSubpacketGenerator generator = new PGPSignatureSubpacketGenerator();
183        applyTo((SignatureSubpackets) subpackets, generator);
184        return generator.generate();
185    }
186}