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

ebourg / jsign / #381

22 Sep 2025 04:50PM UTC coverage: 83.226% (+0.1%) from 83.103%
#381

push

ebourg
Reorganized the documentation (command line first)

4927 of 5920 relevant lines covered (83.23%)

0.83 hits per line

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

87.18
/jsign-core/src/main/java/net/jsign/cat/CatalogFile.java
1
/*
2
 * Copyright 2022 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.cat;
18

19
import java.io.File;
20
import java.io.IOException;
21
import java.nio.ByteBuffer;
22
import java.nio.channels.Channels;
23
import java.nio.channels.SeekableByteChannel;
24
import java.nio.file.Files;
25
import java.nio.file.StandardOpenOption;
26
import java.util.ArrayList;
27
import java.util.Collections;
28
import java.util.List;
29

30
import org.bouncycastle.asn1.ASN1Object;
31
import org.bouncycastle.cms.CMSException;
32
import org.bouncycastle.cms.CMSSignedData;
33
import org.bouncycastle.cms.CMSTypedData;
34
import org.bouncycastle.cms.SignerInformationStore;
35
import org.bouncycastle.util.CollectionStore;
36

37
import net.jsign.DigestAlgorithm;
38
import net.jsign.Signable;
39
import net.jsign.SignatureUtils;
40

41
/**
42
 * Windows Catalog file.
43
 *
44
 * @see <a href="https://docs.microsoft.com/en-us/windows-hardware/drivers/install/catalog-files">Windows Drivers - Catalog Files and Digital Signatures</a>
45
 * @since 4.2
46
 */
47
public class CatalogFile implements Signable {
48

49
    private final SeekableByteChannel channel;
50

51
    private CMSSignedData signedData;
52

53
    /**
54
     * Tells if the specified file is a Windows catalog file.
55
     *
56
     * @param file the file to check
57
     * @return <code>true</code> if the file is a Windows catalog, <code>false</code> otherwise
58
     */
59
    public static boolean isCatalogFile(File file) {
60
        if (!file.exists() || !file.isFile()) {
1✔
61
            return false;
×
62
        }
63

64
        try {
65
            CatalogFile catFile = new CatalogFile(file);
1✔
66
            catFile.close();
1✔
67
            return true;
1✔
68
        } catch (IOException e) {
1✔
69
            return false;
1✔
70
        }
71
    }
72

73
    /**
74
     * Create a Windows catalog from the specified file.
75
     *
76
     * @param file the file to open
77
     * @throws IOException if an I/O error occurs
78
     */
79
    public CatalogFile(File file) throws IOException {
80
        this(Files.newByteChannel(file.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE));
1✔
81
    }
1✔
82

83
    /**
84
     * Create a Windows catalog from the specified channel.
85
     *
86
     * @param channel the channel to read the file from
87
     * @throws IOException if an I/O error occurs
88
     */
89
    public CatalogFile(SeekableByteChannel channel) throws IOException {
1✔
90
        this.channel = channel;
1✔
91

92
        channel.position(0);
1✔
93

94
        try {
95
            signedData = new CMSSignedData(Channels.newInputStream(channel));
1✔
96
        } catch (CMSException e) {
1✔
97
            channel.close();
1✔
98
            throw new IOException("Catalog file format error", e);
1✔
99
        }
1✔
100
    }
1✔
101

102
    @Override
103
    public void close() throws IOException {
104
        channel.close();
1✔
105
    }
1✔
106

107
    @Override
108
    public CMSTypedData createSignedContent(DigestAlgorithm digestAlgorithm) {
109
        return signedData.getSignedContent();
1✔
110
    }
111

112
    @Override
113
    public byte[] computeDigest(DigestAlgorithm digest) {
114
        throw new UnsupportedOperationException();
×
115
    }
116

117
    @Override
118
    public ASN1Object createIndirectData(DigestAlgorithm digestAlgorithm) {
119
        throw new UnsupportedOperationException();
×
120
    }
121

122
    @Override
123
    public List<CMSSignedData> getSignatures() throws IOException {
124
        if (signedData.getSignerInfos().size() > 0) {
1✔
125
            return SignatureUtils.getSignatures(signedData);
1✔
126
        } else {
127
            return new ArrayList<>();
1✔
128
        }
129
    }
130

131
    @Override
132
    public void setSignature(CMSSignedData signature) {
133
        if (signature != null) {
1✔
134
            signedData = signature;
1✔
135
        } else {
136
            // remove the signatures and the certificates
137
            try {
138
                signedData = CMSSignedData.replaceSigners(signedData, new SignerInformationStore(Collections.emptyList()));
1✔
139
                CollectionStore<?> emptyStore = new CollectionStore<>(Collections.emptyList());
1✔
140
                signedData = CMSSignedData.replaceCertificatesAndCRLs(signedData, emptyStore, emptyStore, emptyStore);
1✔
141
            } catch (CMSException e) {
×
142
                throw new RuntimeException(e);
×
143
            }
1✔
144
        }
145
    }
1✔
146

147
    @Override
148
    public void save() throws IOException {
149
        channel.position(0);
1✔
150
        channel.truncate(0);
1✔
151
        channel.write(ByteBuffer.wrap(signedData.getEncoded("DER")));
1✔
152
    }
1✔
153
}
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