28
28
import java .io .*;
29
29
import java .math .BigInteger ;
30
30
import java .net .URI ;
31
+ import java .security .interfaces .EdECPrivateKey ;
32
+ import java .security .spec .InvalidParameterSpecException ;
33
+ import java .security .spec .PSSParameterSpec ;
31
34
import java .util .*;
32
35
import java .security .cert .X509Certificate ;
33
36
import java .security .cert .CertificateException ;
34
37
import java .security .cert .X509CRL ;
35
38
import java .security .cert .CRLException ;
36
39
import java .security .cert .CertificateFactory ;
37
40
import java .security .*;
41
+ import java .util .function .Function ;
38
42
43
+ import sun .security .provider .SHAKE256 ;
39
44
import sun .security .timestamp .*;
40
45
import sun .security .util .*;
41
- import sun .security .x509 .AlgorithmId ;
42
- import sun .security .x509 .X509CertImpl ;
43
- import sun .security .x509 .X509CertInfo ;
44
- import sun .security .x509 .X509CRLImpl ;
45
- import sun .security .x509 .X500Name ;
46
+ import sun .security .x509 .*;
46
47
47
48
/**
48
49
* PKCS7 as defined in RSA Laboratories PKCS7 Technical Note. Profile
@@ -86,16 +87,6 @@ private static class SecureRandomHolder {
86
87
}
87
88
}
88
89
89
- /*
90
- * Object identifier for the timestamping key purpose.
91
- */
92
- private static final String KP_TIMESTAMPING_OID = "1.3.6.1.5.5.7.3.8" ;
93
-
94
- /*
95
- * Object identifier for extendedKeyUsage extension
96
- */
97
- private static final String EXTENDED_KEY_USAGE_OID = "2.5.29.37" ;
98
-
99
90
/**
100
91
* Unmarshals a PKCS7 block from its encoded form, parsing the
101
92
* encoded bytes from the InputStream.
@@ -178,9 +169,9 @@ private void parse(DerInputStream derin)
178
169
private void parse (DerInputStream derin , boolean oldStyle )
179
170
throws IOException
180
171
{
181
- contentInfo = new ContentInfo (derin , oldStyle );
182
- contentType = contentInfo .contentType ;
183
- DerValue content = contentInfo .getContent ();
172
+ ContentInfo block = new ContentInfo (derin , oldStyle );
173
+ contentType = block .contentType ;
174
+ DerValue content = block .getContent ();
184
175
185
176
if (contentType .equals (ContentInfo .SIGNED_DATA_OID )) {
186
177
parseSignedData (content );
@@ -189,6 +180,7 @@ private void parse(DerInputStream derin, boolean oldStyle)
189
180
parseOldSignedData (content );
190
181
} else if (contentType .equals (ContentInfo .NETSCAPE_CERT_SEQUENCE_OID )){
191
182
parseNetscapeCertChain (content );
183
+ contentInfo = block ; // Maybe useless, just do not let it be null
192
184
} else {
193
185
throw new ParsingException ("content type " + contentType +
194
186
" not supported." );
@@ -773,6 +765,128 @@ public boolean isOldStyle() {
773
765
return this .oldStyle ;
774
766
}
775
767
768
+ /**
769
+ * Generate a PKCS7 data block.
770
+ *
771
+ * @param sigalg signature algorithm to be used
772
+ * @param sigProvider (optional) provider
773
+ * @param privateKey signer's private ky
774
+ * @param signerChain signer's certificate chain
775
+ * @param content the content to sign
776
+ * @param internalsf whether the content should be include in output
777
+ * @param directsign if the content is signed directly or thru authattrs
778
+ * @param ts (optional) timestamper
779
+ * @return the pkcs7 output in an array
780
+ * @throws SignatureException if signing failed
781
+ * @throws InvalidKeyException if key cannot be used
782
+ * @throws IOException should not happen here, all byte array
783
+ * @throws NoSuchAlgorithmException if siglag is bad
784
+ */
785
+ public static byte [] generateNewSignedData (
786
+ String sigalg , Provider sigProvider ,
787
+ PrivateKey privateKey , X509Certificate [] signerChain ,
788
+ byte [] content , boolean internalsf , boolean directsign ,
789
+ Function <byte [], PKCS9Attributes > ts )
790
+ throws SignatureException , InvalidKeyException , IOException ,
791
+ NoSuchAlgorithmException {
792
+
793
+ Signature signer = SignatureUtil .fromKey (sigalg , privateKey , sigProvider );
794
+
795
+ AlgorithmId digAlgID = SignatureUtil .getDigestAlgInPkcs7SignerInfo (
796
+ signer , sigalg , privateKey , directsign );
797
+ AlgorithmId sigAlgID = SignatureUtil .fromSignature (signer , privateKey );
798
+
799
+ PKCS9Attributes authAttrs = null ;
800
+ if (!directsign ) {
801
+ // MessageDigest
802
+ byte [] md ;
803
+ String digAlgName = digAlgID .getName ();
804
+ if (digAlgName .equals ("SHAKE256" ) || digAlgName .equals ("SHAKE256-LEN" )) {
805
+ // No MessageDigest impl for SHAKE256 yet
806
+ var shaker = new SHAKE256 (64 );
807
+ shaker .update (content , 0 , content .length );
808
+ md = shaker .digest ();
809
+ } else {
810
+ md = MessageDigest .getInstance (digAlgName )
811
+ .digest (content );
812
+ }
813
+ // CMSAlgorithmProtection (RFC6211)
814
+ DerOutputStream derAp = new DerOutputStream ();
815
+ DerOutputStream derAlgs = new DerOutputStream ();
816
+ digAlgID .derEncode (derAlgs );
817
+ DerOutputStream derSigAlg = new DerOutputStream ();
818
+ sigAlgID .derEncode (derSigAlg );
819
+ derAlgs .writeImplicit ((byte )0xA1 , derSigAlg );
820
+ derAp .write (DerValue .tag_Sequence , derAlgs );
821
+ authAttrs = new PKCS9Attributes (new PKCS9Attribute []{
822
+ new PKCS9Attribute (PKCS9Attribute .CONTENT_TYPE_OID ,
823
+ ContentInfo .DATA_OID ),
824
+ new PKCS9Attribute (PKCS9Attribute .SIGNING_TIME_OID ,
825
+ new Date ()),
826
+ new PKCS9Attribute (PKCS9Attribute .CMS_ALGORITHM_PROTECTION_OID ,
827
+ derAp .toByteArray ()),
828
+ new PKCS9Attribute (PKCS9Attribute .MESSAGE_DIGEST_OID ,
829
+ md )
830
+ });
831
+ signer .update (authAttrs .getDerEncoding ());
832
+ } else {
833
+ signer .update (content );
834
+ }
835
+
836
+ byte [] signature = signer .sign ();
837
+
838
+ return constructToken (signature , signerChain ,
839
+ internalsf ? content : null ,
840
+ authAttrs ,
841
+ ts == null ? null : ts .apply (signature ),
842
+ digAlgID ,
843
+ sigAlgID );
844
+ }
845
+
846
+ /**
847
+ * Assemble a PKCS7 token from its components
848
+ * @param signature the signature
849
+ * @param signerChain the signer's certificate chain
850
+ * @param content (optional) encapsulated content
851
+ * @param authAttrs (optional) authenticated attributes
852
+ * @param unauthAttrs (optional) unauthenticated attributes
853
+ * @param digAlgID digest algorithm identifier
854
+ * @param encAlgID encryption algorithm identifier
855
+ * @return the token in a byte array
856
+ * @throws IOException should not happen here, all byte array
857
+ */
858
+ private static byte [] constructToken (byte [] signature ,
859
+ X509Certificate [] signerChain ,
860
+ byte [] content ,
861
+ PKCS9Attributes authAttrs ,
862
+ PKCS9Attributes unauthAttrs ,
863
+ AlgorithmId digAlgID ,
864
+ AlgorithmId encAlgID )
865
+ throws IOException {
866
+ // Create the SignerInfo
867
+ X500Name issuerName =
868
+ X500Name .asX500Name (signerChain [0 ].getIssuerX500Principal ());
869
+ BigInteger serialNumber = signerChain [0 ].getSerialNumber ();
870
+ SignerInfo signerInfo = new SignerInfo (issuerName , serialNumber ,
871
+ digAlgID , authAttrs ,
872
+ encAlgID ,
873
+ signature , unauthAttrs );
874
+
875
+ // Create the PKCS #7 signed data message
876
+ SignerInfo [] signerInfos = {signerInfo };
877
+ AlgorithmId [] algorithms = {signerInfo .getDigestAlgorithmId ()};
878
+ // Include or exclude content
879
+ ContentInfo contentInfo = (content == null )
880
+ ? new ContentInfo (ContentInfo .DATA_OID , null )
881
+ : new ContentInfo (content );
882
+ PKCS7 pkcs7 = new PKCS7 (algorithms , contentInfo ,
883
+ signerChain , signerInfos );
884
+ ByteArrayOutputStream p7out = new ByteArrayOutputStream ();
885
+ pkcs7 .encodeSignedData (p7out );
886
+
887
+ return p7out .toByteArray ();
888
+ }
889
+
776
890
/**
777
891
* Assembles a PKCS #7 signed data message that optionally includes a
778
892
* signature timestamp.
@@ -797,6 +911,7 @@ public boolean isOldStyle() {
797
911
* generating the signature timestamp or while generating the signed
798
912
* data message.
799
913
*/
914
+ @ Deprecated (since ="16" , forRemoval =true )
800
915
public static byte [] generateSignedData (byte [] signature ,
801
916
X509Certificate [] signerChain ,
802
917
byte [] content ,
@@ -824,34 +939,59 @@ public static byte[] generateSignedData(byte[] signature,
824
939
tsToken )});
825
940
}
826
941
827
- // Create the SignerInfo
828
- X500Name issuerName =
829
- X500Name .asX500Name (signerChain [0 ].getIssuerX500Principal ());
830
- BigInteger serialNumber = signerChain [0 ].getSerialNumber ();
831
- String encAlg = AlgorithmId .getEncAlgFromSigAlg (signatureAlgorithm );
832
- String digAlg = AlgorithmId .getDigAlgFromSigAlg (signatureAlgorithm );
833
- if (digAlg == null ) {
834
- throw new UnsupportedOperationException ("Unable to determine " +
835
- "the digest algorithm from the signature algorithm." );
836
- }
837
- SignerInfo signerInfo = new SignerInfo (issuerName , serialNumber ,
838
- AlgorithmId .get (digAlg ), null ,
839
- AlgorithmId .get (encAlg ),
840
- signature , unauthAttrs );
942
+ return constructToken (signature , signerChain , content ,
943
+ null ,
944
+ unauthAttrs ,
945
+ AlgorithmId .get (SignatureUtil .extractDigestAlgFromDwithE (signatureAlgorithm )),
946
+ AlgorithmId .get (signatureAlgorithm ));
947
+ }
841
948
842
- // Create the PKCS #7 signed data message
843
- SignerInfo [] signerInfos = { signerInfo };
844
- AlgorithmId [] algorithms = { signerInfo . getDigestAlgorithmId ()};
845
- // Include or exclude content
846
- ContentInfo contentInfo = ( content == null )
847
- ? new ContentInfo ( ContentInfo . DATA_OID , null )
848
- : new ContentInfo ( content );
849
- PKCS7 pkcs7 = new PKCS7 ( algorithms , contentInfo ,
850
- signerChain , signerInfos );
851
- ByteArrayOutputStream p7out = new ByteArrayOutputStream ();
852
- pkcs7 . encodeSignedData ( p7out );
949
+ /**
950
+ * Examine the certificate for a Subject Information Access extension
951
+ * (<a href="http://tools.ietf.org/html/rfc5280">RFC 5280</a>).
952
+ * The extension's {@code accessMethod} field should contain the object
953
+ * identifier defined for timestamping: 1.3.6.1.5.5.7.48.3 and its
954
+ * {@code accessLocation} field should contain an HTTP or HTTPS URL.
955
+ *
956
+ * @param tsaCertificate (optional) X.509 certificate for the TSA.
957
+ * @return An HTTP or HTTPS URI or null if none was found.
958
+ */
959
+ public static URI getTimestampingURI ( X509Certificate tsaCertificate ) {
853
960
854
- return p7out .toByteArray ();
961
+ if (tsaCertificate == null ) {
962
+ return null ;
963
+ }
964
+ // Parse the extensions
965
+ try {
966
+ byte [] extensionValue = tsaCertificate .getExtensionValue
967
+ (KnownOIDs .SubjectInfoAccess .value ());
968
+ if (extensionValue == null ) {
969
+ return null ;
970
+ }
971
+ DerInputStream der = new DerInputStream (extensionValue );
972
+ der = new DerInputStream (der .getOctetString ());
973
+ DerValue [] derValue = der .getSequence (5 );
974
+ AccessDescription description ;
975
+ GeneralName location ;
976
+ URIName uri ;
977
+ for (int i = 0 ; i < derValue .length ; i ++) {
978
+ description = new AccessDescription (derValue [i ]);
979
+ if (description .getAccessMethod ()
980
+ .equals (ObjectIdentifier .of (KnownOIDs .AD_TimeStamping ))) {
981
+ location = description .getAccessLocation ();
982
+ if (location .getType () == GeneralNameInterface .NAME_URI ) {
983
+ uri = (URIName ) location .getName ();
984
+ if (uri .getScheme ().equalsIgnoreCase ("http" ) ||
985
+ uri .getScheme ().equalsIgnoreCase ("https" )) {
986
+ return uri .getURI ();
987
+ }
988
+ }
989
+ }
990
+ }
991
+ } catch (IOException ioe ) {
992
+ // ignore
993
+ }
994
+ return null ;
855
995
}
856
996
857
997
/**
@@ -873,7 +1013,7 @@ public static byte[] generateSignedData(byte[] signature,
873
1013
* @throws CertificateException The exception is thrown if the TSA's
874
1014
* certificate is not permitted for timestamping.
875
1015
*/
876
- private static byte [] generateTimestampToken (Timestamper tsa ,
1016
+ public static byte [] generateTimestampToken (Timestamper tsa ,
877
1017
String tSAPolicyID ,
878
1018
String tSADigestAlg ,
879
1019
byte [] toBeTimestamped )
@@ -944,13 +1084,13 @@ private static byte[] generateTimestampToken(Timestamper tsa,
944
1084
"Certificate not included in timestamp token" );
945
1085
} else {
946
1086
if (!cert .getCriticalExtensionOIDs ().contains (
947
- EXTENDED_KEY_USAGE_OID )) {
1087
+ KnownOIDs . extendedKeyUsage . value () )) {
948
1088
throw new CertificateException (
949
1089
"Certificate is not valid for timestamping" );
950
1090
}
951
1091
List <String > keyPurposes = cert .getExtendedKeyUsage ();
952
1092
if (keyPurposes == null ||
953
- !keyPurposes .contains (KP_TIMESTAMPING_OID )) {
1093
+ !keyPurposes .contains (KnownOIDs . KP_TimeStamping . value () )) {
954
1094
throw new CertificateException (
955
1095
"Certificate is not valid for timestamping" );
956
1096
}
0 commit comments