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

ebourg / jsign / #371

20 May 2025 09:49AM UTC coverage: 83.194% (-0.1%) from 83.31%
#371

push

ebourg
Allow the keystore parameter to be specified with the ETOKEN storetype to distinguish between multiple connected devices (#300)

0 of 6 new or added lines in 2 files covered. (0.0%)

36 existing lines in 3 files now uncovered.

4861 of 5843 relevant lines covered (83.19%)

0.83 hits per line

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

50.0
/jsign-crypto/src/main/java/net/jsign/OpenSC.java
1
/*
2
 * Copyright 2023 Emmanuel Bourg
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.File;
20
import java.io.IOException;
21
import java.security.Provider;
22
import java.security.ProviderException;
23
import java.util.ArrayList;
24
import java.util.List;
25

26
import sun.security.pkcs11.wrapper.CK_SLOT_INFO;
27
import sun.security.pkcs11.wrapper.CK_TOKEN_INFO;
28
import sun.security.pkcs11.wrapper.PKCS11;
29
import sun.security.pkcs11.wrapper.PKCS11Exception;
30

31
/**
32
 * Helper class for working with OpenSC.
33
 *
34
 * @since 5.0
35
 */
36
class OpenSC {
×
37

38
    /**
39
     * Returns the security provider for OpenSC.
40
     *
41
     * @param name the name of the token
42
     * @return the OpenSC security provider
43
     * @throws ProviderException thrown if the provider can't be initialized
44
     */
45
    static Provider getProvider(String name) {
46
        return ProviderUtils.createSunPKCS11Provider(getSunPKCS11Configuration(name));
×
47
    }
48

49
    /**
50
     * Returns the SunPKCS11 configuration for OpenSC.
51
     *
52
     * @param name the name or the slot id of the token
53
     * @throws ProviderException thrown if the PKCS11 modules cannot be found
54
     */
55
    static String getSunPKCS11Configuration(String name) {
56
        File library = getOpenSCLibrary();
1✔
57
        if (!library.exists()) {
1✔
58
            throw new ProviderException("OpenSC PKCS11 module is not installed (" + library + " is missing)");
×
59
        }
60

61
        long slot;
62
        try {
63
            try {
64
                slot = Integer.parseInt(name);
×
65
            } catch (Exception e) {
1✔
66
                slot = getTokenSlot(library, name);
×
67
            }
×
68
        } catch (Exception e) {
1✔
69
            throw new ProviderException(e);
1✔
UNCOV
70
        }
×
71

UNCOV
72
        return new PKCS11Configuration().name("opensc").library(library).slot(slot).toString();
×
73
    }
74

75
    /**
76
     * Returns the slot index associated to the token.
77
     *
78
     * @param libraryPath the path to the PKCS11 library
79
     * @param name        the partial name of the token
80
     */
81
    static long getTokenSlot(File libraryPath, String name) throws PKCS11Exception, IOException {
82
        PKCS11 pkcs11 = PKCS11.getInstance(libraryPath.getAbsolutePath(), "C_GetFunctionList", null, false);
1✔
83
        long[] slots = pkcs11.C_GetSlotList(true);
1✔
84

85
        List<String> descriptions = new ArrayList<>();
1✔
86
        List<Long> matches = new ArrayList<>();
1✔
87
        for (long slot : slots) {
1✔
UNCOV
88
            CK_SLOT_INFO info = pkcs11.C_GetSlotInfo(slot);
×
UNCOV
89
            String description = new String(info.slotDescription).trim();
×
90
            if (name == null || description.toLowerCase().contains(name.toLowerCase())) {
×
91
                CK_TOKEN_INFO tokenInfo = pkcs11.C_GetTokenInfo(slot);
×
92
                String label = new String(tokenInfo.label).trim();
×
93
                if (label.equals("OpenPGP card (User PIN (sig))")) {
×
94
                    // OpenPGP cards such as the Nitrokey 3 are exposed as two slots with the same name by OpenSC.
95
                    // Only the first one contains the signing key and the certificate, so the second one is ignored.
UNCOV
96
                    continue;
×
97
                }
98

UNCOV
99
                matches.add(slot);
×
100
            }
101
            descriptions.add(description);
×
102
        }
103

104
        if (matches.size() == 1) {
1✔
UNCOV
105
            return matches.get(0);
×
106
        }
107

108
        if (matches.isEmpty()) {
1✔
109
            throw new RuntimeException(descriptions.isEmpty() ? "No PKCS11 token found" : "No PKCS11 token found matching '" + name + "' (available tokens: " + String.join(", ", descriptions) + ")");
1✔
110
        } else {
UNCOV
111
            throw new RuntimeException("Multiple PKCS11 tokens found" + (name != null ? " matching '" + name + "'" : "") + ", please specify the name of the token to use (available tokens: " + String.join(", ", descriptions) + ")");
×
112
        }
113
    }
114

115
    /**
116
     * Attempts to locate the opensc-pkcs11 library on the system.
117
     */
118
    static File getOpenSCLibrary() {
119
        String osname = System.getProperty("os.name");
1✔
120
        String arch = System.getProperty("sun.arch.data.model");
1✔
121

122
        if (osname.contains("Windows")) {
1✔
123
            String programfiles;
UNCOV
124
            if ("32".equals(arch) && System.getenv("ProgramFiles(x86)") != null) {
×
UNCOV
125
                programfiles = System.getenv("ProgramFiles(x86)");
×
126
            } else {
127
                programfiles = System.getenv("ProgramFiles");
×
128
            }
129
            return new File(programfiles + "/OpenSC Project/OpenSC/pkcs11/opensc-pkcs11.dll");
×
130

131
        } else if (osname.contains("Mac")) {
1✔
UNCOV
132
            return new File("/Library/OpenSC/lib/opensc-pkcs11.so");
×
133

134
        } else {
135
            // Linux
136
            List<String> paths = new ArrayList<>();
1✔
137
            if ("32".equals(arch)) {
1✔
UNCOV
138
                paths.add("/usr/lib/opensc-pkcs11.so");
×
UNCOV
139
                paths.add("/usr/lib/i386-linux-gnu/opensc-pkcs11.so");
×
140
                paths.add("/usr/lib/arm-linux-gnueabi/opensc-pkcs11.so");
×
141
                paths.add("/usr/lib/arm-linux-gnueabihf/opensc-pkcs11.so");
×
142
            } else {
143
                paths.add("/usr/lib64/opensc-pkcs11.so");
1✔
144
                paths.add("/usr/lib/x86_64-linux-gnu/opensc-pkcs11.so");
1✔
145
                paths.add("/usr/lib/aarch64-linux-gnu/opensc-pkcs11.so");
1✔
146
                paths.add("/usr/lib/mips64el-linux-gnuabi64/opensc-pkcs11.so");
1✔
147
                paths.add("/usr/lib/riscv64-linux-gnu/opensc-pkcs11.so");
1✔
148
            }
149

150
            for (String path : paths) {
1✔
151
                File library = new File(path);
1✔
152
                if (library.exists()) {
1✔
153
                    return library;
1✔
154
                }
155
            }
1✔
156

UNCOV
157
            return new File("/usr/local/lib/opensc-pkcs11.so");
×
158
        }
159
    }
160
}
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