xades4j validation error: SigningCertificate property contains one or more certificates that are not part of the certification path - verification

I get a SigningCertificateCertsNotInCertPathException when validating a XADES. The file is signed using a certificate what has a intermediate cert and a root cert:
The section xades:SigningCertificate in the XADES file contains the tree certs. If I build the XADES with only the personal cert in xades:SigningCertificate (using false in FileSystemKeyStoreKeyingDataProvider.returnFullChain), the validation run Ok, but not with the tree certs in xades:SigningCertificate...
Debugging the library, I see that certChainData.getCertificateChain() in method 'verify' of SigningCertificateVerifier.java only contains 2 certs: personal and intermediate certs, but no root cert. I think this could be the reason why SigningCertificateCertsNotInCertPathException arise, but really I don't know
How must I validate the XADES with the tree certs in the xades:SigningCertificate section? My code is this:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new FileReader(SIGNED)));
DOMHelper.useIdAsXmlId(doc.getDocumentElement());
NodeList nl = doc.getElementsByTagNameNS("http://www.w3.org/2000/09/xmldsig#", "Signature");
FileSystemDirectoryCertStore certStore = new FileSystemDirectoryCertStore(CERT_FOLDER);
KeyStore ks;
try (FileInputStream fis = new FileInputStream(CERT_FOLDER + KEY_STORE)) {
ks = KeyStore.getInstance("jks");
ks.load(fis, PASS.toCharArray());
}
CertificateValidationProvider provider = new PKIXCertificateValidationProvider(
ks, false, certStore.getStore());
XadesVerificationProfile profile = new XadesVerificationProfile(provider);
Element sigElem = (Element) nl.item(0);
XAdESVerificationResult r = profile.newVerifier().verify(sigElem, null);
In CERT_FOLDER, I have the two .cer files (root and intermediate certs)
In the KEY_STORE file, I have the three certificates:
Tipo de Almacén de Claves: PKCS12
Proveedor de Almacén de Claves: SUN
Su almacén de claves contiene 3 entradas
personal, 09-dic-2021, PrivateKeyEntry,
Huella Digital de Certificado (SHA1): D8:25:0E:AA:...
intermedio, 09-dic-2021, trustedCertEntry,
Huella Digital de Certificado (SHA1): 80:8B:72:E4:...
raiz, 09-dic-2021, trustedCertEntry,
Huella Digital de Certificado (SHA1): EC:50:35:07:...

If the intermediate certificate is also on the trusted key store (ks) supplied to PKIXCertificateValidationProvider , then you're saying that it can be used as a trust root. During verification, it will be possible to build a certification path consisting of personal < intermedio, as the later is trusted, so no need to keep going.
If your trust root is raiz, then ks should only contain this certificate.

Related

Not able to verify the validity of X509Certificate using Apples App attest root certificate

All I am able to do is validate the generated X509Certificate using its method checkValidity(), but as per the steps mentioned in https://developer.apple.com/documentation/devicecheck/validating_apps_that_connect_to_your_server, we have to validate the X509Certificate using Apple App attest root certificate which is
-----BEGIN CERTIFICATE-----
MIICITCCAaegAwIBAgIQC/O+DvHN0uD7jG5yH2IXmDAKBggqhkjOPQQDAzBSMSYw
JAYDVQQDDB1BcHBsZSBBcHAgQXR0ZXN0YXRpb24gUm9vdCBDQTETMBEGA1UECgwK
QXBwbGUgSW5jLjETMBEGA1UECAwKQ2FsaWZvcm5pYTAeFw0yMDAzMTgxODMyNTNa
Fw00NTAzMTUwMDAwMDBaMFIxJjAkBgNVBAMMHUFwcGxlIEFwcCBBdHRlc3RhdGlv
biBSb290IENBMRMwEQYDVQQKDApBcHBsZSBJbmMuMRMwEQYDVQQIDApDYWxpZm9y
bmlhMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAERTHhmLW07ATaFQIEVwTtT4dyctdh
NbJhFs/Ii2FdCgAHGbpphY3+d8qjuDngIN3WVhQUBHAoMeQ/cLiP1sOUtgjqK9au
Yen1mMEvRq9Sk3Jm5X8U62H+xTD3FE9TgS41o0IwQDAPBgNVHRMBAf8EBTADAQH/
MB0GA1UdDgQWBBSskRBTM72+aEH/pwyp5frq5eWKoTAOBgNVHQ8BAf8EBAMCAQYw
CgYIKoZIzj0EAwMDaAAwZQIwQgFGnByvsiVbpTKwSga0kP0e8EeDS4+sQmTvb7vn
53O5+FRXgeLhpJ06ysC5PrOyAjEAp5U4xDgEgllF7En3VcE3iexZZtKeYnpqtijV
oyFraWVIyd/dganmrduC1bmTBGwD
-----END CERTIFICATE-----
You can have a look at my code:
String decodedCredCert = "
-----BEGIN CERTIFICATE----MIIC4jCCAmmgAwIBAgIGAX66NktmMAoGCCqGSM49BAMCME8xIzAhBgNVBAMMGkFwcGxlIEFwcCBBdHRlc3RhdGlvbiBDQSAxMRMwEQYDVQQKDApBcHBsZSBJbmMuMRMwEQYDVQQIDApDYWxpZm9ybmlhMB4XDTIyMDIwMTExMzM0N1oXDTIyMDIwNDExMzM0N1owgZExSTBHBgNVBAMMQGMwYTY1ZmRjYjE1MDJjNTNmNzUyMzM4NzZlM2ViZTE3NGVlMzYyODkwZDVmZGE3N2RmZTJhMmE2NWQwOTQ1MGYxGjAYBgNVBAsMEUFBQSBDZXJ0aWZpY2F0aW9uMRMwEQYDVQQKDApBcHBsZSBJbmMuMRMwEQYDVQQIDApDYWxpZm9ybmlhMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExooI0SVHKxhLJu+1zDz1VmCQU7SDdoYTBP5FPsl3sn2sYc1De9tzkKCbb/txsvZXDU6cn+HH5Lt3w4+s+wkkmqOB7TCB6jAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIE8DB6BgkqhkiG92NkCAUEbTBrpAMCAQq/iTADAgEBv4kxAwIBAL+JMgMCAQG/iTMDAgEBv4k0IgQgV0EyREI2MzdKVy5jb20uZ2wubWljaGFlbEtvcnMucWGlBgQEc2tzIL+JNgMCAQW/iTcDAgEAv4k5AwIBAL+JOgMCAQAwGQYJKoZIhvdjZAgHBAwwCr+KeAYEBDE1LjIwMwYJKoZIhvdjZAgCBCYwJKEiBCCDM1heaSkW2MvNzjxqor1xYX1U/tdYlXz9a1CiCT/VBjAKBggqhkjOPQQDAgNnADBkAjA4Ek+QKVFVunbBBBbjQ4qfni7vhXVABvbV/ru8CjsSc/fkuKsR4mKmmWjNoFq2vnACMAv5YFRC6rt1fv9vD1duDxv608DOGZtC95H7LOI65RHn0IYiq1iMLfBF
MPUPwJACRw==
-----END CERTIFICATE----- ";
X509Certificate cert1 = getParentCertificate(decodedCredCert);
System.out.println(cert1);
cert1.checkValidity();
where my
This app attest step is to verify the certificate chain. You will get 2 certificates in attestation request i.e. under x5c[0], x5c[1]. These are leaf and intermediate certificates.
To verify the certificate chain, x5c[0] certificate should be signed by x5c[1] and x5c[1] certificate should be signed by Apple App attest root certificate.
Sample code for this
CertificateFactory cf = CertificateFactory.getInstance(AppConstants.X_509);
byte[] credCertByte = Base64.getDecoder().decode(x5c[0]);
X509Certificate credCert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(credCertByte));
byte[] caCertByte = Base64.getDecoder().decode(x5c[1]);
X509Certificate caCert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(caCertByte));
X509Certificate appleAppAttestationRootCaCert = (X509Certificate) cf
.generateCertificate(APPLE_APP_ATTEST_CERT);
credCert.verify(caCert.getPublicKey());
caCert.verify(appleAppAttestationRootCaCert.getPublicKey());
This is the code for NodeJS/Typescript:
import fs from 'fs';
import crypto from 'crypto'
const appleAppAttestationRootCaCert = fs.readFileSync(__dirname + '/../assets/AppleRootCA-G3.pem').toString();
const credCert = new crypto.X509Certificate(Buffer.from(x5c[0], 'base64'))
const caCert = new crypto.X509Certificate(Buffer.from(x5c[1], 'base64'))
const appleCert = new crypto.X509Certificate(appleAppAttestationRootCaCert)
const valid = credCert.verify(caCert.publicKey)
console.log("Valid:", valid)
caCert.verify(appleCert.publicKey);
console.log("Valid with Apple Key:", valid)

SSL implementation with Tungstenite: SSL alert number 42

I created a working WebSocket server with async_tungstenite and async_std.
I now want to add SSL using async_native_tls.
If I understood correctly, this crates provides a function accept which takes a TcpStream, handles the TLS handshake and provides a TlsStream<TcpStream> which should behave like a TcpStream but handles the encryption and decryption behind the scene.
To test the server, I created a self-signed certificate.
Based on that, here is how the code handling new TCP connections evolved:
async fn accept_connection(stream: TcpStream, addr: SocketAddr) {
//Websocket stream
let accept_resut = async_tungstenite::accept_async(stream).await;
if let Err(err) = accept_resut {
println!(
"Error while trying to accept websocket: {}",
err.to_string()
);
panic!(err);
}
println!("New web socket: {}", addr);
}
async fn accept_connection(stream: TcpStream, addr: SocketAddr) {
//Open tls certificate !should be done one time and not for each connection!
let file = File::open("identity.pfx").await.unwrap();
let acceptor_result = TlsAcceptor::new(file, "glacon").await;
if let Err(err) = acceptor_result {
println!("Error while opening certificate: {}", err.to_string());
panic!(err);
}
let acceptor = acceptor_result.unwrap();
//Get a stream where tls is handled
let tls_stream_result = acceptor.accept(stream).await;
if let Err(err) = tls_stream_result {
println!("Error during tls handshake: {}", err.to_string());
panic!(err);
}
let tls_stream = tls_stream_result.unwrap();
//Websocket stream
let accept_resut = async_tungstenite::accept_async(tls_stream).await;
if let Err(err) = accept_resut {
println!(
"Error while trying to accept websocket: {}",
err.to_string()
);
panic!(err);
}
println!("New web socket: {}", addr);
}
With this implementation, I now call from a webpage
const sock = new WebSocket('wss://localhost:8020');
This results in the error:
Error while trying to accept websocket:
IO error: error:14094412:SSL routines:ssl3_read_bytes:sslv3 alert bad certificate:../ssl/record/rec_layer_s3.c:1543:SSL alert number 42
thread 'async-std/runtime' panicked at 'Box<Any>', src/main.rs:57:9
It seems like the handshake was successful as the error does not occur during the acceptor.accept. The error states that the certificate is not valid so here is how I created my self-signed certificate.
The openssl version is 1.1.1f
# Create a key
openssl req -nodes -new -key server.key -out server.csr
# Create the self-signed certificate
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
# Convert the certificate to pfx format
openssl pkcs12 -export -out identity.pfx -inkey server.key -in server.crt
I thought that this problem had to do with security feature from the browser as the "SSL alert number 42" seems to come from the client. I tried to disable this option in Firefox settings
Query OCSP responder servers to confirm the current validity of certificates
I also tried to add my server.crt to the Authorities of the certificate manager.
Neither of these worked.
The problem came from the security features of Firefox.
Firefox detects that the certificate is not signed by an authority and sends back an error.
It seems like adding the certificate to the known authorities does not work.
To avoid this issue, I found this thread which indicates that an exception should be added for the address and port of your development Websocket server.
Go to Settings > Certificates > View Certificates > Servers > Add Exception...
Type in your local server (for me localhost:8020).
Add exception.

How can I use a key.pem file in Netsuite to sign a HTTP request with Suitescript?

I am trying to sign a https request and for that I need to encrypt a digest. From the api I generated both a certificate.pem and a privateKey.pem. I uploaded them both in Netsuite in the Certficate and Key part of the company set up.
My question is mainly how do I now get the privateKey from the file to use with the crypto module?
Here is what I have so far.
"payload" is the data I want to encrypt for my digest and is just a string.
var sKey = keyControl.loadKey('custkey2');
var hmacObj = crypto.createHmac({
algorithm: crypto.HashAlg.SHA256,
key: sKey
});
var updatedHmac = hmacObj.update({
input: payload,
inputEncoding:encode.Encoding.UTF_8
});
var reencoded = encode.convert({
string: updatedHmac,
inputEncoding: encode.Encoding.UTF_8,
outputEncoding: encode.Encoding.BASE_64
});
But when ever I run that in my Suitelet I get an error coming from the "create Hmac".
any help would be more than appreciated thank you.
SS2.0 module N/https/clientCertificate holds the answer. Instead of using https.post() use clientCertificate.post() which can send SSL requests with a digital certificate.
Example that works for me:
/* 1st create certificate in NetSuite UI (Setup > Pereferences > Certificates) */
const certId = 'custcertificate_xy';
/* 2nd use certificates id inside request call */
const response = clientCertificate.post({
url: url,
body: body,
certId: certId,
headers: headers
});
Please note that for some reason NetSuite wanted me to have certificate (*.pem) file in following format:
-----BEGIN PRIVATE KEY-----
{{private key}}
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
{{certificate}}
-----END CERTIFICATE-----

Adding extension in CSR for generating an intermediate certificate

I am generating a Certificate Signing Request for an intermediate certificate. I want to make the certificate a certificate authority (CA), so I want to add the basic constraints extension in CSR. I am currently using the following code
exts = sk_X509_EXTENSION_new_null();
add_ext(exts, x509_req, NID_basic_constraints, "critical,CA:TRUE");
X509_REQ_add_extensions(x509_req, exts);
sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
The add extension function looks like this
int add_ext(STACK_OF(X509_EXTENSION) *sk, X509_REQ* req, int nid, char *value)
{
X509_EXTENSION *ex;
X509V3_CTX ctx;
X509V3_set_ctx_nodb(&ctx);
X509V3_set_ctx(&ctx, NULL, NULL, req, NULL, 0);
ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
if (!ex)
{
log("X509V3_EXT_conf_nid generated error", cspsdk::Logging::LOG_LEVEL_INFO);
return 0;
}
sk_X509_EXTENSION_push(sk, ex);
return 1;
}
The problem is that after getting signed, the certificate has the CA value of basic constraints extension set to false. I am at a loss here. Can anybody point out the issue.
Your issuer can choose to override the constraints like CA: False even though you requested for CA: True. You need to contact them unless you are self-signing your certs.
openssl x509 -in your-signed-cert.pem -text -noout
Please check if the output contains "CA:True".

X509Certificate2 the server mode SSL must use a certificate with the associated private key

I use SslStream to build a web server. However, the code below throws an exception when AuthenticateAsServer.
static X509Certificate cert;
protected virtual Stream GetStream(TcpClient client)
{
var ss = new SslStream(client.GetStream(), false);
if (cert == null)
{
cert = X509Certificate2.CreateFromCertFile("test.cer");
}
ss.AuthenticateAsServer(cert, false, System.Security.Authentication.SslProtocols.Tls, true);
return ss;
}
I've already used X509Certificate2 to load the cert file why it still throw the exception (The server mode SSL must use a certificate with the associated private key)?
The cert file was created using the following command:
makecert
-pe Exportable private key
-n "CN=localhost" Subject name
-ss my Certificate store name
-sr LocalMachine Certificate store location
-a sha1 Signature algorithm
-sky signature Subject key type is for signature purposes
-r Make a self-signed cert
"test.cer" Output filename
makecert.exe -r -pe -n "CN=localhost" -sky exchange -sv server.pvk server.cer
pvk2pfx -pvk server.pvk -spc server.cer -pfx server.pfx -pi <password>
var certificate = new X509Certificate("path\server.pfx", "password");