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

ebourg / jsign / #418

23 Jul 2026 12:50PM UTC coverage: 81.28% (+0.5%) from 80.829%
#418

push

ebourg
CodeQL workflow

5397 of 6640 relevant lines covered (81.28%)

0.81 hits per line

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

89.74
/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.util.ArrayList;
25
import java.util.Collections;
26
import java.util.List;
27

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

35
import net.jsign.ChannelUtils;
36
import net.jsign.DigestAlgorithm;
37
import net.jsign.Signable;
38
import net.jsign.SignatureUtils;
39

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

48
    private final SeekableByteChannel channel;
49

50
    private CMSSignedData signedData;
51

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

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

72
    /**
73
     * Create a Windows catalog from the specified file.
74
     *
75
     * @param file the file to open
76
     * @throws IOException if an I/O error occurs
77
     */
78
    public CatalogFile(File file) throws IOException {
79
        this(ChannelUtils.openReadWriteOrReadOnly(file));
1✔
80
    }
1✔
81

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

91
        channel.position(0);
1✔
92

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

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

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

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

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

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

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

146
    @Override
147
    public void save() throws IOException {
148
        channel.position(0);
1✔
149
        channel.truncate(0);
1✔
150
        channel.write(ByteBuffer.wrap(signedData.getEncoded("DER")));
1✔
151
    }
1✔
152
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc