Skip to content

Commit 04d9ae1

Browse files
author
Olesja Aarma
committed
Merge branch 'RM-4445_mobile-id_decrypt' into 'SID'
RM-4445: implement decryption using MID in lib See merge request cdoc2/cdoc2-java-ref-impl!89
2 parents 3bc5f16 + 8734b5e commit 04d9ae1

29 files changed

+891
-303
lines changed

cdoc2-cli/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,11 @@ or with Smart-ID:
179179
java -jar target/cdoc2-cli-*.jar decrypt -sid=38001085718 -f /tmp/smartid.cdoc --output /tmp
180180
```
181181

182+
or with Mobile-ID:
183+
184+
```
185+
java -jar target/cdoc2-cli-*.jar decrypt -mid=51307149560 -mid-phone=+37269930366 -f /tmp/mobileid.cdoc --output /tmp
186+
```
182187

183188
### Decrypting with server scenario
184189
Server must be running, see cdoc2-capsule-server/README.md for starting the server
File renamed without changes.

cdoc2-cli/src/main/java/ee/cyber/cdoc2/cli/DecryptionKeyExclusiveArgument.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,8 @@ public class DecryptionKeyExclusiveArgument {
4141
paramLabel = "SID", description = "ID code for smart-id decryption")
4242
private String sid;
4343

44-
@CommandLine.Option(names = {"-mid", "--mobile-id"},
45-
paramLabel = "MID", description = "ID code for mobile-id decryption")
46-
private String mid;
44+
@CommandLine.ArgGroup(exclusive = false)
45+
private MobileIdArguments midArguments;
4746

4847
public File getPrivKeyFile() {
4948
return this.privKeyFile;
@@ -66,15 +65,25 @@ public boolean isWithSid() {
6665
}
6766

6867
public boolean isWithMid() {
69-
return this.mid != null;
68+
return this.midArguments != null;
7069
}
7170

7271
public String getSid() {
7372
return this.sid;
7473
}
7574

7675
public String getMid() {
77-
return this.mid;
76+
if (isWithMid()) {
77+
return this.midArguments.getMid();
78+
}
79+
return null;
80+
}
81+
82+
public String getMidPhone() {
83+
if (isWithMid()) {
84+
return this.midArguments.getMidPhone();
85+
}
86+
return null;
7887
}
7988

8089
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package ee.cyber.cdoc2.cli;
2+
3+
import picocli.CommandLine;
4+
5+
6+
/**
7+
* Arguments for Mobile ID decryption/re-encryption commands,
8+
* used inside {@link DecryptionKeyExclusiveArgument}
9+
*/
10+
public class MobileIdArguments {
11+
12+
@CommandLine.Option(names = {"-mid", "--mobile-id"},
13+
paramLabel = "MID", description = "ID code for mobile-id decryption")
14+
private String mid;
15+
16+
@CommandLine.Option(names = {"-mid-phone", "--mobile-id-phone"},
17+
paramLabel = "MID", description = "Phone number for mobile-id decryption")
18+
private String midPhone;
19+
20+
public String getMid() {
21+
if (null != this.midPhone && null == this.mid) {
22+
throw new IllegalArgumentException("Required identity code must be present to process");
23+
}
24+
return this.mid;
25+
}
26+
27+
public String getMidPhone() {
28+
if (null != this.mid && null == this.midPhone) {
29+
throw new IllegalArgumentException("Required phone number is missing");
30+
}
31+
return this.midPhone;
32+
}
33+
34+
}

cdoc2-cli/src/main/java/ee/cyber/cdoc2/cli/commands/CDocDecryptCmd.java

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
import java.io.File;
1111
import java.nio.file.InvalidPathException;
12-
import java.security.GeneralSecurityException;
1312
import java.util.List;
1413
import java.util.Map;
1514

@@ -18,7 +17,7 @@
1817
import ee.cyber.cdoc2.CDocDecrypter;
1918

2019
import static ee.cyber.cdoc2.cli.util.CDocCommonHelper.getKeyCapsulesClientFactory;
21-
import static ee.cyber.cdoc2.cli.util.CDocCommonHelper.initKeyShareClientFactory;
20+
import static ee.cyber.cdoc2.cli.util.CDocDecryptionHelper.addKeySharesIfAny;
2221
import static ee.cyber.cdoc2.cli.util.CDocDecryptionHelper.getDecrypterWithFilesExtraction;
2322
import static ee.cyber.cdoc2.cli.util.CDocDecryptionHelper.getDecryptionKeyMaterial;
2423
import static ee.cyber.cdoc2.cli.util.CDocDecryptionHelper.getSmartCardDecryptionKeyMaterial;
@@ -93,18 +92,12 @@ public Void call() throws Exception {
9392
keyCapsulesClientFactory
9493
);
9594

96-
addKeySharesIfAny(cDocDecrypter);
95+
addKeySharesIfAny(cDocDecrypter, this.exclusive);
9796

9897
System.out.println("Decrypting " + this.cdocFile + " to " + this.outputPath.getAbsolutePath());
9998
List<String> extractedFileNames = cDocDecrypter.decrypt();
10099
extractedFileNames.forEach(System.out::println);
101100
return null;
102101
}
103102

104-
private void addKeySharesIfAny(CDocDecrypter cDocDecrypter) throws GeneralSecurityException {
105-
if (null != this.exclusive && (this.exclusive.isWithSid() || this.exclusive.isWithMid())) {
106-
cDocDecrypter.withKeyShares(initKeyShareClientFactory());
107-
}
108-
}
109-
110103
}

cdoc2-cli/src/main/java/ee/cyber/cdoc2/cli/commands/CDocListCmd.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import picocli.CommandLine.Option;
2020

2121
import static ee.cyber.cdoc2.cli.util.CDocCommonHelper.getKeyCapsulesClientFactory;
22+
import static ee.cyber.cdoc2.cli.util.CDocDecryptionHelper.addKeySharesIfAny;
2223
import static ee.cyber.cdoc2.cli.util.CDocDecryptionHelper.getDecryptionKeyMaterial;
2324
import static ee.cyber.cdoc2.cli.util.CDocDecryptionHelper.getSmartCardDecryptionKeyMaterial;
2425

@@ -78,6 +79,8 @@ public Void call() throws Exception {
7879
.withKeyServers(keyCapsulesClientFactory)
7980
.withRecipient(decryptionKeyMaterial);
8081

82+
addKeySharesIfAny(cDocDecrypter, this.exclusive);
83+
8184
System.out.println("Listing contents of " + cdocFile);
8285
List<ArchiveEntry> files = cDocDecrypter.list();
8386
if (!verbose) {

cdoc2-cli/src/main/java/ee/cyber/cdoc2/cli/util/CDocCommonHelper.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
1212
import ee.cyber.cdoc2.config.KeyCapsuleClientConfigurationImpl;
1313
import ee.cyber.cdoc2.config.KeySharesConfiguration;
1414
import ee.cyber.cdoc2.config.KeySharesConfigurationImpl;
15+
import ee.cyber.cdoc2.config.MobileIdClientConfigurationImpl;
1516
import ee.cyber.cdoc2.config.SmartIdClientConfigurationImpl;
1617
import ee.cyber.cdoc2.exceptions.ConfigurationLoadingException;
1718
import ee.cyber.cdoc2.util.Resources;
1819

1920
import static ee.cyber.cdoc2.config.Cdoc2ConfigurationProperties.KEY_SHARES_PROPERTIES;
21+
import static ee.cyber.cdoc2.config.Cdoc2ConfigurationProperties.MOBILE_ID_PROPERTIES;
2022
import static ee.cyber.cdoc2.config.Cdoc2ConfigurationProperties.SMART_ID_PROPERTIES;
2123
import static ee.cyber.cdoc2.config.PropertiesLoader.loadProperties;
2224

@@ -72,12 +74,11 @@ private static KeySharesConfiguration loadKeySharesConfiguration() {
7274
Properties properties = loadProperties(propertiesFilePath);
7375
Cdoc2Configuration configuration = new KeySharesConfigurationImpl(properties);
7476
CDoc2ConfigurationProvider.initKeyShareClientConfig(configuration);
75-
loadSmartIdConfiguration();
7677

7778
return configuration.keySharesConfiguration();
7879
}
7980

80-
private static void loadSmartIdConfiguration() throws ConfigurationLoadingException {
81+
static void loadSmartIdConfiguration() throws ConfigurationLoadingException {
8182
String propertiesFilePath = System.getProperty(
8283
SMART_ID_PROPERTIES,
8384
"config/smart-id/" + SMART_ID_PROPERTIES
@@ -91,4 +92,18 @@ private static void loadSmartIdConfiguration() throws ConfigurationLoadingExcept
9192
CDoc2ConfigurationProvider.initSmartIdClientConfig(configuration);
9293
}
9394

95+
static void loadMobileIdConfiguration() throws ConfigurationLoadingException {
96+
String propertiesFilePath = System.getProperty(
97+
MOBILE_ID_PROPERTIES,
98+
"config/mobile-id/" + MOBILE_ID_PROPERTIES
99+
);
100+
if (null == propertiesFilePath) {
101+
throw new ConfigurationLoadingException("Mobile ID configuration property is missing");
102+
}
103+
Properties properties = loadProperties(propertiesFilePath);
104+
Cdoc2Configuration configuration = new MobileIdClientConfigurationImpl(properties);
105+
106+
CDoc2ConfigurationProvider.initMobileIdClientConfig(configuration);
107+
}
108+
94109
}

cdoc2-cli/src/main/java/ee/cyber/cdoc2/cli/util/CDocDecryptionHelper.java

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import ee.cyber.cdoc2.container.recipients.Recipient;
1919
import ee.cyber.cdoc2.crypto.PemTools;
2020
import ee.cyber.cdoc2.crypto.Pkcs11Tools;
21-
import ee.cyber.cdoc2.crypto.SemanticIdentification;
21+
import ee.cyber.cdoc2.crypto.AuthenticationIdentifier;
2222
import ee.cyber.cdoc2.crypto.keymaterial.DecryptionKeyMaterial;
2323
import ee.cyber.cdoc2.crypto.keymaterial.LabeledPassword;
2424
import ee.cyber.cdoc2.crypto.keymaterial.LabeledSecret;
@@ -29,7 +29,12 @@
2929
import javax.annotation.Nonnull;
3030
import javax.annotation.Nullable;
3131

32+
import static ee.cyber.cdoc2.cli.util.CDocCommonHelper.initKeyShareClientFactory;
33+
import static ee.cyber.cdoc2.cli.util.CDocCommonHelper.loadMobileIdConfiguration;
34+
import static ee.cyber.cdoc2.cli.util.CDocCommonHelper.loadSmartIdConfiguration;
3235
import static ee.cyber.cdoc2.config.Cdoc2ConfigurationProperties.PKCS11_LIBRARY_PROPERTY;
36+
import static ee.cyber.cdoc2.crypto.AuthenticationIdentifier.createSemanticsIdentifier;
37+
import static ee.sk.mid.MidInputUtil.getValidatedPhoneNumber;
3338

3439

3540
/**
@@ -111,6 +116,12 @@ public static DecryptionKeyMaterial getDecryptionKeyMaterial(
111116
decryptionKm = getSidDecryptionKeyMaterial(decryptArguments.getSid());
112117
}
113118

119+
if (isWithMid && decryptionKm == null) {
120+
decryptionKm = getMidDecryptionKeyMaterial(
121+
decryptArguments.getMid(), decryptArguments.getMidPhone()
122+
);
123+
}
124+
114125
// this must be final initialization
115126
if (decryptionKm == null) {
116127
decryptionKm = getKeyPairDecryptionKeyMaterial(p12, privKeyFile);
@@ -120,10 +131,25 @@ public static DecryptionKeyMaterial getDecryptionKeyMaterial(
120131
}
121132

122133
private static DecryptionKeyMaterial getSidDecryptionKeyMaterial(String idCode) {
123-
SemanticIdentification semanticIdentifier = SemanticIdentification
124-
.forKeyShares(idCode, SemanticIdentification.AuthenticationType.SID);
134+
loadSmartIdConfiguration();
135+
AuthenticationIdentifier authIdentifier = AuthenticationIdentifier.forKeyShares(
136+
createSemanticsIdentifier(idCode), AuthenticationIdentifier.AuthenticationType.SID
137+
);
138+
139+
return DecryptionKeyMaterial.fromAuthMeans(authIdentifier);
140+
}
141+
142+
private static DecryptionKeyMaterial getMidDecryptionKeyMaterial(
143+
String idCode,
144+
String phoneNumber
145+
) {
146+
loadMobileIdConfiguration();
147+
AuthenticationIdentifier authIdentifier = AuthenticationIdentifier.forMidDecryption(
148+
createSemanticsIdentifier(idCode),
149+
getValidatedPhoneNumber(phoneNumber)
150+
);
125151

126-
return DecryptionKeyMaterial.fromAuthMeans(semanticIdentifier);
152+
return DecryptionKeyMaterial.fromAuthMeans(authIdentifier);
127153
}
128154

129155
private static DecryptionKeyMaterial getPasswordDecryptionKeyMaterial(
@@ -238,6 +264,20 @@ public static LabeledPassword getLabeledPassword(
238264
return labeledPassword;
239265
}
240266

267+
/**
268+
* Create Key Shares configuration if decryption is arranged with Smart-ID or Mobile-ID.
269+
* @param cDocDecrypter CDOC decrypter builder
270+
* @param exclusiveArgs decryption exclusive CLI options
271+
*/
272+
public static void addKeySharesIfAny(
273+
CDocDecrypter cDocDecrypter,
274+
DecryptionKeyExclusiveArgument exclusiveArgs
275+
) throws GeneralSecurityException {
276+
if (null != exclusiveArgs && (exclusiveArgs.isWithSid() || exclusiveArgs.isWithMid())) {
277+
cDocDecrypter.withKeyShares(initKeyShareClientFactory());
278+
}
279+
}
280+
241281
/**
242282
* When label was not provided and recipients contains only one recipient, then set labeledPassword
243283
* label value to recipient.label value
Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
package ee.cyber.cdoc2.client.mobileid;
22

3-
import java.util.regex.Matcher;
4-
import java.util.regex.Pattern;
5-
63
import static ee.cyber.cdoc2.util.IdCodeValidationUtil.getValidatedIdentityCode;
4+
import static ee.sk.mid.MidInputUtil.getValidatedPhoneNumber;
75

86

97
/**
@@ -16,21 +14,9 @@ public record MobileIdUserData(
1614
String identityCode
1715
) {
1816

19-
private static final String PHONE_NUMBER_PATTERN = "\\+37\\d{5,10}";
20-
private static final Pattern phoneNrPpattern = Pattern.compile(PHONE_NUMBER_PATTERN);
21-
2217
public MobileIdUserData(String phoneNumber, String identityCode) {
2318
this.phoneNumber = getValidatedPhoneNumber(phoneNumber);
2419
this.identityCode = getValidatedIdentityCode(identityCode);
2520
}
2621

27-
private String getValidatedPhoneNumber(String phoneNr) {
28-
Matcher matcher = phoneNrPpattern.matcher(phoneNr);
29-
if (!matcher.matches()) {
30-
throw new IllegalArgumentException("Invalid phone number: " + phoneNr);
31-
}
32-
33-
return phoneNr;
34-
}
35-
3622
}

cdoc2-lib/src/main/java/ee/cyber/cdoc2/container/recipients/RecipientFactory.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -445,8 +445,7 @@ public static KeySharesRecipient buildKeySharesRecipient(
445445

446446
// plain ETSI Identifier is a value 'etsi/PNOEE-48010010101', extracted from the
447447
// semantics identifier
448-
String plainEtsiIdentifier
449-
= keyShareMaterial.semanticIdentifier().getEtsiIdentifier();
448+
String plainEtsiIdentifier = keyShareMaterial.authIdentifier().getEtsiIdentifier();
450449
String info = "CDOC2kek" + fmkEncMethod + plainEtsiIdentifier;
451450
byte[] kek = hkdf.expand(kekPm, info.getBytes(StandardCharsets.UTF_8), Crypto.KEK_LEN_BYTES);
452451

0 commit comments

Comments
 (0)