• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ebourg / jsign / #360

05 Feb 2025 09:39AM UTC coverage: 83.213% (-0.006%) from 83.219%
#360

push

ebourg
Always propagate the underlying exception when throwing a SignerException

2 of 3 new or added lines in 1 file covered. (66.67%)

4 existing lines in 2 files now uncovered.

4739 of 5695 relevant lines covered (83.21%)

0.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.25
/jsign-core/src/main/java/net/jsign/Signable.java
1
/**
2
 * Copyright 2019 Emmanuel Bourg and contributors
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
package net.jsign;
18

19
import java.io.Closeable;
20
import java.io.File;
21
import java.io.IOException;
22
import java.nio.charset.Charset;
23
import java.security.MessageDigest;
24
import java.security.cert.Certificate;
25
import java.security.cert.CertificateEncodingException;
26
import java.security.cert.X509Certificate;
27
import java.util.ArrayList;
28
import java.util.Arrays;
29
import java.util.List;
30
import java.util.ServiceLoader;
31
import java.util.function.Supplier;
32
import java.util.stream.Stream;
33

34
import org.bouncycastle.asn1.ASN1Object;
35
import org.bouncycastle.asn1.cms.Attribute;
36
import org.bouncycastle.asn1.cms.ContentInfo;
37
import org.bouncycastle.cms.CMSSignedData;
38
import org.bouncycastle.cms.CMSTypedData;
39
import org.bouncycastle.cms.PKCS7ProcessableObject;
40

41
import net.jsign.asn1.authenticode.AuthenticodeObjectIdentifiers;
42
import net.jsign.spi.SignableProvider;
43

44
/**
45
 * A file that can be signed with Authenticode.
46
 *
47
 * @author Emmanuel Bourg
48
 */
49
public interface Signable extends Closeable {
50

51
    /**
52
     * Creates the ContentInfo or EncapsulatedContentInfo structure to be signed.
53
     *
54
     * @param digestAlgorithm the digest algorithm to use
55
     * @return the ContentInfo or EncapsulatedContentInfo structure
56
     * @throws IOException if an I/O error occurs
57
     * @since 7.0
58
     */
59
    default CMSTypedData createSignedContent(DigestAlgorithm digestAlgorithm) throws IOException {
60
        return new PKCS7ProcessableObject(AuthenticodeObjectIdentifiers.SPC_INDIRECT_DATA_OBJID, createIndirectData(digestAlgorithm));
1✔
61
    }
62

63
    /**
64
     * Creates the ContentInfo structure to be signed.
65
     *
66
     * @param digestAlgorithm the digest algorithm to use
67
     * @return the ContentInfo structure in ASN.1 format
68
     * @throws IOException if an I/O error occurs
69
     * @since 4.2
70
     * @deprecated Use {@link #createSignedContent(DigestAlgorithm)} instead
71
     */
72
    default ContentInfo createContentInfo(DigestAlgorithm digestAlgorithm) throws IOException {
UNCOV
73
        return new ContentInfo(AuthenticodeObjectIdentifiers.SPC_INDIRECT_DATA_OBJID, createIndirectData(digestAlgorithm));
×
74
    }
75

76
    /**
77
     * Computes the digest of the file.
78
     * 
79
     * @param digest the message digest to update
80
     * @return the digest of the file
81
     * @throws IOException if an I/O error occurs
82
     * @deprecated Use {@link #computeDigest(DigestAlgorithm)} instead
83
     */
84
    default byte[] computeDigest(MessageDigest digest) throws IOException {
85
        return computeDigest(DigestAlgorithm.of(digest.getAlgorithm()));
1✔
86
    }
87

88
    /**
89
     * Computes the digest of the file.
90
     *
91
     * @param digestAlgorithm the digest algorithm to use
92
     * @return the digest of the file
93
     * @throws IOException if an I/O error occurs
94
     * @since 6.0
95
     */
96
    default byte[] computeDigest(DigestAlgorithm digestAlgorithm) throws IOException {
UNCOV
97
        return computeDigest(digestAlgorithm.getMessageDigest());
×
98
    }
99

100
    /**
101
     * Creates the SpcIndirectDataContent structure containing the digest of the file.
102
     * 
103
     * @param digestAlgorithm the digest algorithm to use
104
     * @return the SpcIndirectDataContent structure in ASN.1 format
105
     * @throws IOException if an I/O error occurs
106
     */
107
    ASN1Object createIndirectData(DigestAlgorithm digestAlgorithm) throws IOException;
108

109
    /**
110
     * Creates the signed attributes to include in the signature.
111
     *
112
     * @param certificate the signing certificate
113
     * @since 7.0
114
     */
115
    default List<Attribute> createSignedAttributes(X509Certificate certificate) throws CertificateEncodingException {
UNCOV
116
        return new ArrayList<>();
×
117
    }
118

119
    /**
120
     * Checks if the specified certificate is suitable for signing the file.
121
     *
122
     * @param certificate the certificate to validate
123
     * @throws IOException if an I/O error occurs
124
     * @throws IllegalArgumentException if the certificate doesn't match the publisher identity
125
     * @since 7.0
126
     */
127
    default void validate(Certificate certificate) throws IOException, IllegalArgumentException {
128
    }
1✔
129

130
    /**
131
     * Returns the Authenticode signatures on the file.
132
     * 
133
     * @return the signatures
134
     * @throws IOException if an I/O error occurs
135
     */
136
    List<CMSSignedData> getSignatures() throws IOException;
137

138
    /**
139
     * Sets the signature of the file, overwriting the previous one.
140
     * 
141
     * @param signature the signature to put, or null to remove the signature
142
     * @throws IOException if an I/O error occurs
143
     */
144
    void setSignature(CMSSignedData signature) throws IOException;
145

146
    /**
147
     * Saves the file.
148
     * 
149
     * @throws IOException if an I/O error occurs
150
     */
151
    void save() throws IOException;
152

153
    /**
154
     * Returns a signable object for the file specified.
155
     *
156
     * @param file the file that is intended to be signed
157
     * @return the signable object for the specified file
158
     * @throws IOException if an I/O error occurs
159
     * @throws UnsupportedOperationException if the file specified isn't supported
160
     */
161
    static Signable of(File file) throws IOException {
162
        return of(file, null);
1✔
163
    }
164

165
    /**
166
     * Returns a signable object for the file specified.
167
     *
168
     * @param file     the file that is intended to be signed
169
     * @param encoding the character encoding (for text files only).
170
     *                 If the file has a byte order mark this parameter is ignored.
171
     * @return the signable object for the specified file
172
     * @throws IOException if an I/O error occurs
173
     * @throws UnsupportedOperationException if the file specified isn't supported
174
     */
175
    static Signable of(File file, Charset encoding) throws IOException {
176
        // look for SignableProvider implementations in the classloader that loaded the Jsign classes and in the current classloader
177
        Supplier<ServiceLoader<SignableProvider>> loaders1 = () -> ServiceLoader.load(SignableProvider.class, Signable.class.getClassLoader());
1✔
178
        Supplier<ServiceLoader<SignableProvider>> loaders2 = () -> ServiceLoader.load(SignableProvider.class);
1✔
179

180
        for (Supplier<ServiceLoader<SignableProvider>> loaders : Arrays.asList(loaders1, loaders2)) {
1✔
181
            for (SignableProvider provider : loaders.get()) {
1✔
182
                if (provider.isSupported(file)) {
1✔
183
                    return provider.create(file, encoding);
1✔
184
                }
185
            }
1✔
186
        }
1✔
187

188
        throw new UnsupportedOperationException("Unsupported file: " + file);
1✔
189
    }
190
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc