i get a certificate from an azure key vault :
const certificate = await keyVaultClient.getCertificate(this.keyVaultUri, certificateName, '');
i get the certificate ... first good thing :)
But after i don't find how i can set the certificate in the header of an https request.
i've tried different ways without any success.
Someone knows how i can achieve that. Below test done.
var options = {
hostname: 'url.domain.com',
port: 443,
path: '/method1',
method: 'GET',
agent: false,
rejectUnauthorized: false,
strictSSL: false,
//pfx: certificate.cer.toString('utf8'),
//pfx: certificate.cer.toString('base64'),
pfx: certificate,
passphrase: 'passphrase'
};
const req = https.request(options, (res: any) => { });
Note that if i use the certificate on the drive, it works :
pfx: fs.readFileSync(__dirname + '/my.pfx'),
Thanks in advance
i've found a solution.
First to get the certificate, i've used the method 'getSercret' in place of 'getCertificate' :
let keyVaultClient = new KeyVault.KeyVaultClient(azureCredential);
const secret = await keyVaultClient.getSecret(this.keyVaultUri, secretName, '');
In the header option, i've passed the secret in a buffer with base 64 format :
var options = {
hostname: 'myurl.ti',
port: 443,
path: '/mySuperMethod',
method: 'GET',
agent: false,
rejectUnauthorized: false,
strictSSL: false,
pfx: new Buffer(secret.value, 'base64'),
passphrase: ''
};
You see that the passphrase (password to secure password) is empty. Why ? in fact when you upload a certificate in azure keyvault, you have to mention the password. But after keyvault doesn't keep the password and it's set to blank.
That's known by microsoft and for me it's an issue.
Here an article that explain that : https://thuansoldier.net/7462/
Regards Mathieu
Related
I have a problem when I run get a response for service. There are two services. For the first service, it's working perfectly but in the second I have issue "Error [ERR_TLS_CERT_ALTNAME_INVALID]: Hostname/IP does not match certificate's altnames: Cert is empty". When I used Postman with certificates its works perfectly. What should I set or implement to make it works?
I tried using: checkServerIdentity, rejectUnauthorized: true.
let options = {
hostname: 'ws.aaa.bbb.nn',
path: '/api',
method: 'GET',
key: fs.readFileSync('/private.crt'),
cert: fs.readFileSync('/public.crt'),
passphrase: '***'
};
const req = https.request(options, (res) => {
let body = '';
res.on('data', (chunk)=> {
body += chunk;
console.log(body)
});
});
Should be status code 200.
Seems you got a bad certificate.
Get a correct one or just turn the SSL certificate verification off.
I had the same problem, Just try to set Authorization Type to "Inherit auth from parent".
I am trying to make a request with a p12 file or a pfx, but I can't get it to work. If I use PEM and KEY the code works fine. But Azure Keyvault does not support PEM and KEY. Is there an alternative that works with KEY/PEM certificates?
This is how I generated a p12/pfx file if that is the problem.
openssl pkcs12 -export -out certificate.pfx -inkey 1231181189.key -in
1231181189.pem -certfile CA.pem
Here is an example code, if I comment out cert and key the system does not work,
Error: read ECONNRESET
But if I comment out pfx and passphrase and use pem and key the connection work.
var request = require('request');
var fs = require('fs');
var path = require('path');
var certFile = __dirname + '/certs/1231181189.pem';
var keyFile = __dirname + '/certs/1231181189.key';
var options = {
method: 'POST',
url: 'https://mss.cpc.getswish.net/swish-cpcapi/api/v1/paymentrequests',
headers: { 'Content-Type': 'application/json' },
agentOptions: {
cert: fs.readFileSync(certFile),
key: fs.readFileSync(keyFile),
pfx: fs.readFileSync(__dirname + '/certs/certificate.pfx'),
passphrase: 'swish'
},
body: {
payeePaymentReference: '0123456789',
callbackUrl: 'https://example.com/api/swishcb/paymentrequests',
payerAlias: '4671234768',
payeeAlias: '1231181189',
amount: '100',
currency: 'SEK',
message: 'Kingston USB Flash Drive 8 GB'
},
json: true
};
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(response.headers);
console.log(body);
});
ECONNRESET means the far end -- in your case the endpoint on swish.net -- unceremoniously disconnected from the https client in your nodejs program. It's hard to know precisely why it did so. It's likely due to some sort of security failure. Robust servers don't explain security failures; after all why help cybercreeps? It's possible looking at a log on that server will tell you more.
In the meantime, it's possible the npm request package you use to wrap node's https agent function doesn't know anything about .pfx files or passwords, and therefore attempts to connect without any client certificates.
The pemutils package may allow you to extract the information you need from your .pfx file and use it. Something like this may work (not debugged).
var request = require('request');
var pemutils = require('pemutils');
var fs = require('fs');
var path = require('path');
const pfxFile = __dirname + '/certs/certificate.pfx';
pemutils.fromPfx({
path: pfxFile,
password: 'myPass'
}, function(err, pfxresults) {
if(err) throw err;
var options = {
method: 'POST',
url: 'https://mss.cpc.getswish.net/swish-cpcapi/api/v1/paymentrequests',
headers: { 'Content-Type': 'application/json' },
agentOptions: {
cert: pfxresults.certificate,
key: pfxresults.key,
},
body: {
...
},
json: true
};
...
Notice the .fromPfx method is asynchronous.
I have the same issue with Azure APIM and I also need basic auth for the request.
I send request with axios like below:
const fs = require("fs");
const axios = require("axios");
const https = require("https");
(async function () {
try {
const response = await axios.request({
url: "url",
method: "get",
headers: {
accept: "application/json",
},
auth: {
username: "name",
password: "pw",
},
httpsAgent: new https.Agent({
pfx: fs.readFileSync(
__dirname + "/mycert.pfx"
),
}),
});
console.log(JSON.stringify(response.data));
} catch (error) {
console.log(error);
}
})();
I have the following code, which is run from a express server:
import fetch from 'node-fetch';
let formBody = [];
const dataLogin = {
'username': 'myUser',
'password': 'myPassword'
};
for (let p in dataLogin) {
let encodedKey = encodeURIComponent(p);
let encodedValue = encodeURIComponent(dataLogin[p]);
formBody.push(encodedKey + "=" + encodedValue);
}
formBody = formBody.join("&");
const url = 'https://external-login-api.com';
return fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': formBody.length
},
body: formBody
});
When I run the code I get the following error, despite being able to run the request in Postman with no problems.
{"message":"request to https://external-login-api.com failed, reason: write EPROTO 7316:error:141A318A:SSL routines:tls_process_ske_dhe:dh key too small:openssl\ssl\statem\statem_clnt.c:1472:\n","type":"system","errno":"EPROTO","code":"EPROTO"}
How do I disable SSL verification for this request?
The other way to do is to set your own agent to the fetch call.
const fetch = require('node-fetch');
const https = require('https');
const httpsAgent = new https.Agent({
rejectUnauthorized: false,
});
const response = await fetch(url, {
method: 'POST',
headers: headers,
body: body,
agent: httpsAgent,
});
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
Will ensure you ignore any rejected TLS certificates, or you can set this as an environment variable when running your node service. However this will likely not help, and is probably a bad idea. The SSL error is not because the certificate is invalid (such as a self signed certificate) but instead because of a weak Diffie-Hellman key in the SSL/TLS configuration.
If this a service you're hosting you should look at correcting and improving your TLS/SSL cyphers. See this answer for more information.
The important part is:
You should use 2048-bit Diffie-Hellman groups or larger. You should
not be using 512-bit or 1024-bit Diffie-Hellman groups.
If this is a third party service, you should consider contacting them or using a different service as they are leaving themselves open to the Logjam attack which is also discussed in the answer linked above.
I'm using request in my app to send a POST request over HTTPS with Client Authentication. Request always throws an error Error: Invalid URI "/" and I couldn't do anything to solve it. I've tried used url.parse instead of passing a string but it's still the same.
request.post({
uri: 'https://localhost:5000',
key: credentials.key,
ca: credentials.ca,
cert: credentials.cert,
passphrase: credentials.passphrase,
rejectUnauthorized: false
}, { form: { data: payload }});
Turns out it was caused by passing the second object to request.post, it should be inside the first object.
request.post('https://localhost:5000/', {
key: credentials.key,
ca: credentials.ca,
cert: credentials.cert,
passphrase: credentials.passphrase,
rejectUnauthorized: false,
form: { data: payload }
});
I'm working on a Node.js app that we will call "server A" where users have to provide a client certificate in order to access services.
Simplified example:
/** server setup **/
var serverOptions = {
key: fs.readFileSync('certs/server.key'),
cert: fs.readFileSync('certs/server.crt'),
ca: [fs.readFileSync('certs/ca.crt'), fs.readFileSync('certs/bar.cer'), fs.readFileSync('certs/foo.cer')],
requestCert: true
};
https.createServer(serverOptions, app).listen(SERVER_PORT, '', null, function () {
var host = this.address().address;
var port = this.address().port;
console.log('listening at http://%s:%s', host, port);
});
Everything works as expected, the following code prints the details of the client certificate.
app.get('/', function (req, res) {
/*** Dump ***/
res.contentType('application/json');
res.send(util.inspect(req.socket.getPeerCertificate(true), {colors: true}));
});
However, I would like to be able to use this client certificate obtained in serverA, to make a request to another server called "server B".
options = {
hostname: 'localhost',
port: '3010',
path: '/',
method: 'POST',
headers: {
'Content-Type': 'text/xml;charset=UTF-8',
'Content-Length': serverResponse.length,
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
},
cert: clientCertificate
};
var req = https.request(options, function (res) {
console.log('statusCode: ', res.statusCode);
console.log('headers: ', res.headers);
res.on('data', function(d) {
callback(d);
});
});
The problem is that I have not found a way to get a proper X509 certificate with the getPeerCertificate function, which returns a "custom" object representation of the certificate.
As described in the official documentation, the cert parameter must be provided with the following data :
Public x509 certificate to use. Default null.
Is there a way to get the client certificate in the correct format for that purpose?
I had the same problem and saw your question with no answers, so I'm coming back to post my solution.
The certificate object has a raw field which contains the certificate data you want in byte form. To get it in X509 format, just convert it to base64. So the code you're looking for is:
req.socket.getPeerCertificate(true).raw.toString('base64');
Hope that helps!