45
45
import org .apache .struts2 .ServletActionContext ;
46
46
import org .apache .struts2 .StrutsStatics ;
47
47
import org .apache .struts2 .dispatcher .SessionMap ;
48
+ import org .bouncycastle .asn1 .ASN1ObjectIdentifier ;
49
+ import org .bouncycastle .asn1 .x509 .CertificatePolicies ;
50
+ import org .bouncycastle .asn1 .x509 .Extension ;
51
+ import org .bouncycastle .asn1 .x509 .PolicyInformation ;
52
+ import org .bouncycastle .cert .jcajce .JcaX509ExtensionUtils ;
48
53
import org .bouncycastle .util .encoders .Base64 ;
49
54
import org .digidoc4j .CertificateValidator ;
50
55
import org .digidoc4j .CertificateValidatorBuilder ;
51
56
52
57
import javax .security .auth .x500 .X500Principal ;
53
58
import javax .servlet .http .HttpServletRequest ;
54
59
import java .io .ByteArrayInputStream ;
60
+ import java .io .IOException ;
55
61
import java .io .UnsupportedEncodingException ;
56
62
import java .security .NoSuchAlgorithmException ;
57
63
import java .security .cert .CertificateFactory ;
58
- import java .security .cert .CertificateParsingException ;
59
64
import java .security .cert .X509Certificate ;
60
65
import java .util .*;
66
+ import java .util .stream .Collectors ;
61
67
62
68
import static org .apache .logging .log4j .Level .DEBUG ;
63
69
@@ -121,7 +127,7 @@ public String showLogin() {
121
127
}
122
128
123
129
/**
124
- * @return ERROE if login fails, SUCCESS otherwise
130
+ * @return ERROR if login fails, SUCCESS otherwise
125
131
*/
126
132
@ HTTPMethods (methods = {HTTPMethod .POST })
127
133
public String loginAdmin () {
@@ -442,6 +448,9 @@ private Boolean isCertificateValidForIDCardLogin(X509Certificate certificate) {
442
448
);
443
449
throw new RuntimeException ("No trusted issuer in certificate:" );
444
450
}
451
+ if (!hasValidIssuancePolicy (certificate )) {
452
+ throw new RuntimeException ("No trusted issuance policy found in certificate:" );
453
+ }
445
454
} catch (Throwable throwable ) {
446
455
LOG .catching (DEBUG , throwable );
447
456
LOG .warn (
@@ -454,6 +463,38 @@ private Boolean isCertificateValidForIDCardLogin(X509Certificate certificate) {
454
463
return true ;
455
464
}
456
465
466
+ private Boolean hasValidIssuancePolicy ( X509Certificate certificate ) throws IOException {
467
+ // https://github.com/SK-EID/smart-id-documentation/wiki/Secure-Implementation-Guide#only-accept-certificates-with-trusted-issuance-policy
468
+ final String [] validIssuancePolicyOIDs = {
469
+ "1.3.6.1.4.1.10015.1.1" ,
470
+ "1.3.6.1.4.1.10015.1.2" ,
471
+ "1.3.6.1.4.1.51361.1.1.1" ,
472
+ "1.3.6.1.4.1.51361.1.1.2" ,
473
+ "1.3.6.1.4.1.51361.1.1.3" ,
474
+ "1.3.6.1.4.1.51361.1.1.4" ,
475
+ "1.3.6.1.4.1.51361.1.1.5" ,
476
+ "1.3.6.1.4.1.51361.1.1.6" ,
477
+ "1.3.6.1.4.1.51361.1.1.7" ,
478
+ "1.3.6.1.4.1.51455.1.1.1"
479
+ };
480
+ byte [] extensionValue = certificate .getExtensionValue (
481
+ Extension .certificatePolicies .getId ());
482
+ Objects .requireNonNull (extensionValue , "No certificate policy extension found" );
483
+ LOG .debug ("extensionvalue to parse:{}" , extensionValue );
484
+ CertificatePolicies policies = CertificatePolicies .getInstance (
485
+ JcaX509ExtensionUtils .parseExtensionValue (extensionValue )
486
+ );
487
+ Objects .requireNonNull (policies , "Certificate policy extension value was empty" );
488
+ LOG .debug ("policies found:{}" , policies );
489
+ Set <String > policyIds = Arrays .stream (policies .getPolicyInformation ())
490
+ .map (PolicyInformation ::getPolicyIdentifier )
491
+ .map (ASN1ObjectIdentifier ::getId )
492
+ .collect (Collectors .toSet ());
493
+ LOG .debug ("policy OID's contained:{}" , policyIds );
494
+ return Arrays .stream (validIssuancePolicyOIDs )
495
+ .anyMatch (policyIds ::contains );
496
+ }
497
+
457
498
private Map <String , String > parseSubjectDn (String dn ) {
458
499
Map <String , String > tmp = new HashMap <>();
459
500
0 commit comments