Skip to content

Commit a438a07

Browse files
committed
8213010: Supporting keys created with certmgr.exe
Reviewed-by: valeriep
1 parent dcb8876 commit a438a07

8 files changed

Lines changed: 722 additions & 214 deletions

File tree

src/java.base/share/classes/sun/security/util/ECUtil.java

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -26,17 +26,11 @@
2626
package sun.security.util;
2727

2828
import java.io.IOException;
29-
3029
import java.math.BigInteger;
31-
3230
import java.security.*;
33-
3431
import java.security.interfaces.*;
35-
3632
import java.security.spec.*;
37-
3833
import java.util.Arrays;
39-
4034
import sun.security.x509.X509Key;
4135

4236
public class ECUtil {
@@ -227,5 +221,64 @@ public static String getCurveName(Provider p, ECParameterSpec spec) {
227221
return nameSpec.getName();
228222
}
229223

224+
// Convert the concatenation R and S in into their DER encoding
225+
public static byte[] encodeSignature(byte[] signature) throws SignatureException {
226+
227+
try {
228+
229+
int n = signature.length >> 1;
230+
byte[] bytes = new byte[n];
231+
System.arraycopy(signature, 0, bytes, 0, n);
232+
BigInteger r = new BigInteger(1, bytes);
233+
System.arraycopy(signature, n, bytes, 0, n);
234+
BigInteger s = new BigInteger(1, bytes);
235+
236+
DerOutputStream out = new DerOutputStream(signature.length + 10);
237+
out.putInteger(r);
238+
out.putInteger(s);
239+
DerValue result =
240+
new DerValue(DerValue.tag_Sequence, out.toByteArray());
241+
242+
return result.toByteArray();
243+
244+
} catch (Exception e) {
245+
throw new SignatureException("Could not encode signature", e);
246+
}
247+
}
248+
249+
// Convert the DER encoding of R and S into a concatenation of R and S
250+
public static byte[] decodeSignature(byte[] sig) throws SignatureException {
251+
252+
try {
253+
// Enforce strict DER checking for signatures
254+
DerInputStream in = new DerInputStream(sig, 0, sig.length, false);
255+
DerValue[] values = in.getSequence(2);
256+
257+
// check number of components in the read sequence
258+
// and trailing data
259+
if ((values.length != 2) || (in.available() != 0)) {
260+
throw new IOException("Invalid encoding for signature");
261+
}
262+
263+
BigInteger r = values[0].getPositiveBigInteger();
264+
BigInteger s = values[1].getPositiveBigInteger();
265+
266+
// trim leading zeroes
267+
byte[] rBytes = trimZeroes(r.toByteArray());
268+
byte[] sBytes = trimZeroes(s.toByteArray());
269+
int k = Math.max(rBytes.length, sBytes.length);
270+
// r and s each occupy half the array
271+
byte[] result = new byte[k << 1];
272+
System.arraycopy(rBytes, 0, result, k - rBytes.length,
273+
rBytes.length);
274+
System.arraycopy(sBytes, 0, result, result.length - sBytes.length,
275+
sBytes.length);
276+
return result;
277+
278+
} catch (Exception e) {
279+
throw new SignatureException("Invalid encoding for signature", e);
280+
}
281+
}
282+
230283
private ECUtil() {}
231284
}

src/jdk.crypto.ec/share/classes/sun/security/ec/ECDSASignature.java

Lines changed: 2 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,7 @@
2525

2626
package sun.security.ec;
2727

28-
import java.io.IOException;
2928
import java.nio.ByteBuffer;
30-
import java.math.BigInteger;
3129

3230
import java.security.*;
3331
import java.security.interfaces.*;
@@ -453,7 +451,7 @@ protected byte[] engineSign() throws SignatureException {
453451
if (p1363Format) {
454452
return sig;
455453
} else {
456-
return encodeSignature(sig);
454+
return ECUtil.encodeSignature(sig);
457455
}
458456
}
459457

@@ -476,7 +474,7 @@ protected boolean engineVerify(byte[] signature) throws SignatureException {
476474
if (p1363Format) {
477475
sig = signature;
478476
} else {
479-
sig = decodeSignature(signature);
477+
sig = ECUtil.decodeSignature(signature);
480478
}
481479

482480
try {
@@ -515,79 +513,6 @@ protected AlgorithmParameters engineGetParameters() {
515513
return null;
516514
}
517515

518-
// Convert the concatenation of R and S into their DER encoding
519-
private byte[] encodeSignature(byte[] signature) throws SignatureException {
520-
521-
try {
522-
523-
int n = signature.length >> 1;
524-
byte[] bytes = new byte[n];
525-
System.arraycopy(signature, 0, bytes, 0, n);
526-
BigInteger r = new BigInteger(1, bytes);
527-
System.arraycopy(signature, n, bytes, 0, n);
528-
BigInteger s = new BigInteger(1, bytes);
529-
530-
DerOutputStream out = new DerOutputStream(signature.length + 10);
531-
out.putInteger(r);
532-
out.putInteger(s);
533-
DerValue result =
534-
new DerValue(DerValue.tag_Sequence, out.toByteArray());
535-
536-
return result.toByteArray();
537-
538-
} catch (Exception e) {
539-
throw new SignatureException("Could not encode signature", e);
540-
}
541-
}
542-
543-
// Convert the DER encoding of R and S into a concatenation of R and S
544-
private byte[] decodeSignature(byte[] sig) throws SignatureException {
545-
546-
try {
547-
// Enforce strict DER checking for signatures
548-
DerInputStream in = new DerInputStream(sig, 0, sig.length, false);
549-
DerValue[] values = in.getSequence(2);
550-
551-
// check number of components in the read sequence
552-
// and trailing data
553-
if ((values.length != 2) || (in.available() != 0)) {
554-
throw new IOException("Invalid encoding for signature");
555-
}
556-
557-
BigInteger r = values[0].getPositiveBigInteger();
558-
BigInteger s = values[1].getPositiveBigInteger();
559-
560-
// trim leading zeroes
561-
byte[] rBytes = trimZeroes(r.toByteArray());
562-
byte[] sBytes = trimZeroes(s.toByteArray());
563-
int k = Math.max(rBytes.length, sBytes.length);
564-
// r and s each occupy half the array
565-
byte[] result = new byte[k << 1];
566-
System.arraycopy(rBytes, 0, result, k - rBytes.length,
567-
rBytes.length);
568-
System.arraycopy(sBytes, 0, result, result.length - sBytes.length,
569-
sBytes.length);
570-
return result;
571-
572-
} catch (Exception e) {
573-
throw new SignatureException("Invalid encoding for signature", e);
574-
}
575-
}
576-
577-
// trim leading (most significant) zeroes from the result
578-
private static byte[] trimZeroes(byte[] b) {
579-
int i = 0;
580-
while ((i < b.length - 1) && (b[i] == 0)) {
581-
i++;
582-
}
583-
if (i == 0) {
584-
return b;
585-
}
586-
byte[] t = new byte[b.length - i];
587-
System.arraycopy(b, i, t, 0, t.length);
588-
return t;
589-
}
590-
591516
/**
592517
* Signs the digest using the private key.
593518
*

src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CKey.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,13 @@
2525

2626
package sun.security.mscapi;
2727

28+
import sun.security.util.KeyUtil;
2829
import sun.security.util.Length;
2930

31+
import java.math.BigInteger;
3032
import java.security.Key;
33+
import java.security.interfaces.ECPrivateKey;
34+
import java.security.interfaces.ECPublicKey;
3135

3236
/**
3337
* The handle for a key using the Microsoft Crypto API.
@@ -100,4 +104,51 @@ public String getAlgorithm() {
100104
protected native static String getContainerName(long hCryptProv);
101105

102106
protected native static String getKeyType(long hCryptKey);
107+
108+
// This java method generates EC BLOBs for public key or private key.
109+
// See https://docs.microsoft.com/en-us/windows/desktop/api/bcrypt/ns-bcrypt-_bcrypt_ecckey_blob
110+
static byte[] generateECBlob(Key k) {
111+
112+
int keyBitLength = KeyUtil.getKeySize(k);
113+
int keyLen = (keyBitLength + 7) / 8;
114+
boolean isPrivate = k instanceof ECPrivateKey;
115+
116+
byte[] keyBlob = new byte[8 + keyLen * (isPrivate ? 3 : 2)];
117+
keyBlob[0] = 'E';
118+
keyBlob[1] = 'C';
119+
keyBlob[2] = 'S';
120+
if (isPrivate) {
121+
keyBlob[3] = (byte) (keyBitLength == 256 ? '2'
122+
: (keyBitLength == 384 ? '4' : '6'));
123+
} else {
124+
keyBlob[3] = (byte) (keyBitLength == 256 ? '1'
125+
: (keyBitLength == 384 ? '3' : '5'));
126+
}
127+
BigInteger x;
128+
BigInteger y;
129+
// Fill the array in reverse order (s -> y -> x -> len) in case
130+
// one BigInteger encoding has an extra 0 at the beginning
131+
if (isPrivate) {
132+
// We can keep X and Y zero and it still works
133+
ECPrivateKey prk = (ECPrivateKey)k;
134+
BigInteger s = prk.getS();
135+
byte[] bs = s.toByteArray();
136+
System.arraycopy(
137+
bs, 0,
138+
keyBlob, 8 + keyLen + keyLen + keyLen - bs.length,
139+
bs.length);
140+
} else {
141+
ECPublicKey puk = (ECPublicKey)k;
142+
x = puk.getW().getAffineX();
143+
y = puk.getW().getAffineY();
144+
byte[] by = y.toByteArray();
145+
System.arraycopy(by, 0, keyBlob, 8 + keyLen + keyLen - by.length,
146+
by.length);
147+
byte[] bx = x.toByteArray();
148+
System.arraycopy(bx, 0, keyBlob, 8 + keyLen - bx.length, bx.length);
149+
}
150+
keyBlob[4] = (byte) keyLen;
151+
keyBlob[5] = keyBlob[6] = keyBlob[7] = 0;
152+
return keyBlob;
153+
}
103154
}

src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CKeyStore.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -759,12 +759,12 @@ private void generateCertificateChain(String alias,
759759
}
760760

761761
/**
762-
* Generates RSA key and certificate chain from the private key handle,
762+
* Generates key and certificate chain from the private key handle,
763763
* collection of certificates and stores the result into key entries.
764764
* <p>
765765
* This method is called by native codes in security.cpp.
766766
*/
767-
private void generateRSAKeyAndCertificateChain(String alias,
767+
private void generateKeyAndCertificateChain(boolean isRSA, String alias,
768768
long hCryptProv, long hCryptKey, int keyLength,
769769
Collection<? extends Certificate> certCollection) {
770770
try {
@@ -777,7 +777,7 @@ private void generateRSAKeyAndCertificateChain(String alias,
777777
certChain[i] = (X509Certificate) iter.next();
778778
}
779779
storeWithUniqueAlias(alias, new KeyEntry(alias,
780-
CPrivateKey.of("RSA", hCryptProv, hCryptKey, keyLength),
780+
CPrivateKey.of(isRSA ? "RSA" : "EC", hCryptProv, hCryptKey, keyLength),
781781
certChain));
782782
} catch (Throwable e) {
783783
// Ignore the exception and skip this entry

0 commit comments

Comments
 (0)