I'm trying to run the 'create-passenger-name-record-sample-nodejs' example code. It requires a secret and PCC as shown below:
endpoint: 'https://api.test.sabre.com',
secret: process.env.SWS_API_SECRET || '',
pcc: process.env.SWS_API_PCC || '',
};
According to the documentation, the secret above is a base64 encoding of 'V1:userid:group:domain'.
I have created an account but it is not clear to me where to obtain the pieces necessary to construct the concatenated string above and also where to obtain the PCC.
Is anyone able to provide some guidance?
Thanks.
_Username and password should be provided by your account executive if you have a Sabre subscription. If you do not have a Sabre subscription, you should be able to obtain sample credentials to test in test environments. You can find your test credentials under "Applications" when you click on "My account". The procedure to encode a token, if needed, is located at https://developer.sabre.com/guides/travel-agency/developer-guides/rest-apis-token-credentials.
The solution is to base64 encode the ClientID. Then base64 encode the ClientSecret. Then join those results with a ':' and base64 encode the joined string. This then is used as the value of the 'secret' field in the JSON snippet above.
I'm setting up an OpenID flow for my application and want to test Private Key JWT client certificate authentication with Microsoft Active Directory. That is, I want to use a certificate rather than client secrets to authenticate my application when requesting id and access tokens. However, when making the token request I receive the following error:
{
"error":"invalid_client",
"error_description":"AADSTS700027: Client assertion contains an invalid signature. [Reason - The key was not found., Please visit 'https://developer.microsoft.com/en-us/graph/graph-explorer' and query for 'https://graph.microsoft.com/beta/applications/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' to see configured keys]\r\nTrace ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\r\nCorrelation ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\r\nTimestamp: 2019-09-26 22:24:19Z",
"error_codes":[
700027
],
"timestamp":"2019-09-26 22:24:19Z",
"trace_id":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"correlation_id":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"error_uri":"https://login.microsoftonline.com/error?code=700027"
}
I'm generating the private key and certificate using the following command:
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes
I've uploaded cert.pem to my app registration in the azure portal.
In my application, I'm using the Nimbus JOSE + JWT library to construct the JWT and the Nimbus OAuth 2.0 SDK with OpenID Connect extensions to manage the OpenID flow. Here are the Javadoc pages for each of those packages respectively:
https://www.javadoc.io/doc/com.nimbusds/nimbus-jose-jwt/7.8
https://www.javadoc.io/doc/com.nimbusds/oauth2-oidc-sdk/6.14
I've verified that the key and certificate are in the PEM format by checking that they contain the -----BEGIN PRIVATE KEY----- and -----BEGIN CERTIFICATE----- headers and the corresponding footers.
As per the error, I visited https://developer.microsoft.com/en-us/graph/graph-explorer , logged in on the left, and then sent a query using the given unredacted url. Doing this gave me the error:
{
"error": {
"code": "Request_ResourceNotFound",
"message": "Resource 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' does not exist or one of its queried reference-property objects are not present.",
"innerError": {
"request-id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"date": "2019-09-26T23:47:37"
}
}
My current implementation looks as follows.
val privateKeyString = File(keyFilePath).readText()
val certificateString = File(certFilePath).readText()
val certObject = JWK.parseFromPEMEncodedX509Cert(certificateString)
val privateKeyJWK = JWK.parseFromPEMEncodedObjects(privateKeyString)
val privateKey = RSAKey.parse(privateKeyJWK.toJSONObject())
val privateKeyJWT = PrivateKeyJWT(
ClientID(configuration.clientId), // clientId retrieved from the app reg on the azure portal
providerMetadata.tokenEndpointURI, // login.microsoftonline.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/oauth2/token
JWSAlgorithm.RS256,
privateKey.toRSAPrivateKey(),
certObject.keyID,
null)
val tokenReq = TokenRequest(
providerMetadata.tokenEndpointURI,
privateKeyJWT,
AuthorizationCodeGrant(authCode, // authCode received from previous step of the OpenID flow
URI(configuration.redirectURI)) // the application's login page. This has been registered in
// the app reg on the azure portal.
)
val tokenHTTPResponse: HTTPResponse? = tokenReq.toHTTPRequest().send()
val tokenResponse = OIDCTokenResponse.parse(tokenHTTPResponse) // response fails with the described error
There are several steps that could be going wrong here but I haven't been able to narrow it down:
My Key generation could be wrong. Perhaps I am using a key and cert that is not the expected format?
My parsing of the keys using the Nimbus Library could be wrong. Stepping through the code during a request and inspecting the data objects seems to indicate that it is parsing all the components out of the file. Whether or not it is parsing those components correctly is unclear.
My construction of the Private Key JWT may be flawed.
The construction of the Token Request may be flawed.
The configuration of my application registration on the Azure Portal may be wrong.
Any pointers on how to narrow this down or resolve this issue would be greatly appreciated!
The simple answer to why this doesn't work is that Azure Active Directory does not support Private Key JWT Authentication. The code as written works, but only for services that support Private Key JWT Authentication.
There is a simpler way to generate a JWK from the Nimbus JOSE+JWT library:
https://connect2id.com/products/nimbus-jose-jwt/examples/jwk-generation#rsa
Is your OAuth 2.0 client registered for private_key_jwt authentication at the token endpoint?
I want to the pin the public key of my server so that any request made to the server has to have that public key (this is to prevent proxies like Charles sniffing the data).
I had done something similar in Android with Volley.
How can I do the same with Flutter?
Create your client with a SecurityContext with no trusted roots to force the bad certificate callback, even for a good certificate.
SecurityContext(withTrustedRoots: false);
In the bad certificate callback, parse the DER encoded certificate using the asn1lib package. For example:
ASN1Parser p = ASN1Parser(der);
ASN1Sequence signedCert = p.nextObject() as ASN1Sequence;
ASN1Sequence cert = signedCert.elements[0] as ASN1Sequence;
ASN1Sequence pubKeyElement = cert.elements[6] as ASN1Sequence;
ASN1BitString pubKeyBits = pubKeyElement.elements[1] as ASN1BitString;
List<int> encodedPubKey = pubKeyBits.stringValue;
// could stop here and compare the encoded key parts, or...
// parse them into their modulus/exponent parts, and test those
// (assumes RSA public key)
ASN1Parser rsaParser = ASN1Parser(encodedPubKey);
ASN1Sequence keySeq = rsaParser.nextObject() as ASN1Sequence;
ASN1Integer modulus = keySeq.elements[0] as ASN1Integer;
ASN1Integer exponent = keySeq.elements[1] as ASN1Integer;
print(modulus.valueAsBigInteger);
print(exponent);
Key rotation reduces risk. When an attacker obtains an old server hard drive or backup file and gets an old server private key from it, they cannot impersonate the current server if the key has been rotated. Therefore always generate a new key when updating certificates. Configure the client to trust the old key and the new key. Wait for your users to update to the new version of the client. Then deploy the new key to your servers. Then you can remove the old key from the client.
Server key pinning is only needed if you're not rotating keys. That's bad security practice.
You should do certificate pinning with rotation. I have added example code in How to do SSL pinning via self generated signed certificates in flutter?
I want to build a desktop application and be able to publish product keys or serial numbers.Before the user can use the application he will be requested to enter the product key/serial number.
Similar to Microsoft Office when they provide keys like XXXX-XXXX-XXXX-XXXX
The idea I have is to sell the app based on licenses and providing product key for every device seems more professional than accounts (usernames and passwords).
so my questions are:
1) Is it possible to accomplish this with electron?
2) Can you advice me wether I should go for serial numbers (if it is doable) or accounts? or are there better options?
3) if you answered the second question. Please state why?
Edit for 2021: I'd like to revise this answer, as it has generated a lot of inquiries on the comparison I made between license keys and user accounts. I previously would almost always recommended utilizing user accounts for licensing Electron apps, but I've since changed my position to be a little more nuanced. For most Electron apps, license keys will do just fine.
Adding license key (synonymous with product key) validation to an Electron app can be pretty straight forward. First, you would want to somehow generate a license key for each user. This can be done using cryptography, or it can be done by generating a 'random' license key string and storing it in a database and then building a CRUD licensing server that can verify that a given license key is "valid."
For cryptographic license keys, you can take some information from the customer, e.g. their order number or an email address, and create a 'signature' of it using RSA cryptography. Using Node, that would look something like this:
const crypto = require('crypto')
// Generate a new keypair
const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', {
// Using a larger key size, such as 2048, would be more secure
// but will result in longer signatures.
modulusLength: 512,
privateKeyEncoding: { type: 'pkcs1', format: 'pem' },
publicKeyEncoding: { type: 'pkcs1', format: 'pem' },
})
// Some data we're going to use to generate a license key from
const data = 'user#store.example'
// Create a RSA signer
const signer = crypto.createSign('rsa-sha256')
signer.update(data)
// Encode the original data
const encoded = Buffer.from(data).toString('base64')
// Generate a signature for the data
const signature = signer.sign(privateKey, 'hex')
// Combine the encoded data and signature to create a license key
const licenseKey = `${encoded}.${signature}`
console.log({ privateKey, publicKey, licenseKey })
Then, to validate the license key within your Electron app, you would want to cryptographically 'verify' the key's authenticity by embedding the public (not the private!) key generated above into your application code base:
// Split the license key's data and the signature
const [encoded, signature] = licenseKey.split('.')
const data = Buffer.from(encoded, 'base64').toString()
// Create an RSA verifier
const verifier = crypto.createVerify('rsa-sha256')
verifier.update(data)
// Verify the signature for the data using the public key
const valid = verifier.verify(publicKey, signature, 'hex')
console.log({ valid, data })
Generating and verifying the authenticity of cryptographically signed license keys like this will work great for a lot of simple licensing needs. They're relatively simple, and they work great offline, but sometimes verifying that a license key is 'valid' isn't enough. Sometimes requirements dictate that license keys are not perpetual (i.e. 'valid' forever), or they call for more complicated licensing systems, such as one where only a limited number of devices (or seats) can use the app at one time. Or perhaps the license key needs a renewable expiration date. That's where a license server can come in.
A license server can help manage a license's activation, expirations, among other things, such as user accounts used to associate multiple licenses or feature-licenses with a single user or team. I don't recommend user accounts unless you have a specific need for them, e.g. you need additional user profile information, or you need to associate multiple licenses with a single user.
But in case you aren't particularly keen on writing and maintaining your own in-house licensing system, or you just don't want to deal with writing your own license key generator like the one above, I’m the founder of a software licensing API called Keygen which can help you get up and running quickly without having to write and host your own license server. :)
Keygen is a typical HTTP JSON API service (i.e. there’s no software that you need to package with your app). It can be used in any programming language and with frameworks like Electron.
In its simplest form, validating a license key with Keygen is as easy as hitting a single JSON API endpoint (feel free to run this in a terminal):
curl -X POST https://api.keygen.sh/v1/accounts/demo/licenses/actions/validate-key \
-d '{
"meta": {
"key": "C1B6DE-39A6E3-DE1529-8559A0-4AF593-V3"
}
}'
I recently put together an example of adding license key validation, as well as device activation and management, to an Electron app. You can check out that repo on GitHub: https://github.com/keygen-sh/example-electron-license-activation.
I hope that answers your question and gives you a few insights. Happy to answer any other questions you have, as I've implemented licensing a few times now for Electron apps. :)
YES but concerning the software registration mechanism, IT IS HARD and it needs a lot of testing too.
If 90% of your users have internet access you should definitely go with the user accounts or some OAUTH 2.0 Plug and play thing (login with facebook/gmail/whatever)
I built a software licensing architecture from scratch using crypto and the fs module , and it was quite a journey (year) !
Making a good registration mechanism for your software from scratch is not recommended , electron makes it harder because the source code is relatively exposed.
That being said , if you really wanna go that way , bcrypt is good at this (hashs), you need a unique user identifier to hash , you also need some kind of persistence (preferably a file ) where you can store the user license , and you need to hide the salt that you are using for hashing either by hashing the hash... or storing small bits of it in separate files.
this will make a good starting point for licensing but it's far from being fully secured.
Hope it helps !
There are many services out there which help you add license key based software licensing to your app. And to ensure your customers don't reuse the key, you would need a strong device fingerprinting algorithm.
You can try out Cryptlex. It offers a very robust licensing solution with advanced device fingerprinting algo. You can check out the Node.js example on Github to add licensing to your electron app.
Yes, it is possible.
I myself desired this feature, and I found related solutions such as paid video tutorials, online solutions [with Keygen], and other random hacks, but I wanted something that is offline and free, so I created my own repository for myself/others to use. Here's how it works.
Overview
Install secure-electron-license-keys-cli. (ie. npm i -g secure-electron-license-keys-cli).
Create a license key by running secure-electron-license-keys-cli. This generates a public.key, private.key and license.data.
Keep private.key safe, but stick public.key and license.data in the root of your Electron app.
Install secure-electron-license-keys. (ie. npm i secure-electron-license-keys).
In your main.js file, review this sample code and add the necessary binding.
const {
app,
BrowserWindow,
ipcMain,
} = require("electron");
const SecureElectronLicenseKeys = require("secure-electron-license-keys");
const path = require("path");
const fs = require("fs");
const crypto = require("crypto");
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win;
async function createWindow() {
// Create the browser window.
win = new BrowserWindow({
width: 800,
height: 600,
title: "App title",
webPreferences: {
preload: path.join(
__dirname,
"preload.js"
)
},
});
// Setup bindings for offline license verification
SecureElectronLicenseKeys.mainBindings(ipcMain, win, fs, crypto, {
root: process.cwd(),
version: app.getVersion(),
});
// Load app
win.loadURL("index.html");
// Emitted when the window is closed.
win.on("closed", () => {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
win = null;
});
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on("ready", createWindow);
// Quit when all windows are closed.
app.on("window-all-closed", () => {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== "darwin") {
app.quit();
} else {
SecureElectronLicenseKeys.clearMainBindings(ipcMain);
}
});
In your preload.js file, review the sample code and add the supporting code.
const {
contextBridge,
ipcRenderer
} = require("electron");
const SecureElectronLicenseKeys = require("secure-electron-license-keys");
// Expose protected methods that allow the renderer process to use
// the ipcRenderer without exposing the entire object
contextBridge.exposeInMainWorld("api", {
licenseKeys: SecureElectronLicenseKeys.preloadBindings(ipcRenderer)
});
Review the sample React component how you can verify the validity of your license, and act accordingly within your app.
import React from "react";
import {
validateLicenseRequest,
validateLicenseResponse,
} from "secure-electron-license-keys";
class Component extends React.Component {
constructor(props) {
super(props);
this.checkLicense = this.checkLicense.bind(this);
}
componentWillUnmount() {
window.api.licenseKeys.clearRendererBindings();
}
componentDidMount() {
// Set up binding to listen when the license key is
// validated by the main process
const _ = this;
window.api.licenseKeys.onReceive(validateLicenseResponse, function (data) {
console.log("License response:");
console.log(data);
});
}
// Fire event to check the validity of our license
checkLicense(event) {
window.api.licenseKeys.send(validateLicenseRequest);
}
render() {
return (
<div>
<button onClick={this.checkLicense}>Check license</button>
</div>
);
}
}
export default Component;
You are done!
Further detail
To explain further, the license is validated by a request from the client (ie. front-end) page. The client sends an IPC request to the main (ie. backend) process via this call (window.api.licenseKeys.send(validateLicenseRequest)).
Once this call is received by the backend process (which was hooked up because we set it up with this call (SecureElectronLicenseKeys.mainBindings)), the library code tries to decrypt license.data with public.key. Regardless if this succeeds or not, the success status is sent back to the client page (via IPC).
How to limit license keys by version
What I've explained is quite limited because it doesn't limit the versions of an app you might give to a particular user. secure-electron-license-keys-cli includes flags you may pass when generating the license key to set particular major/minor/patch/expire values for a license.
If you wanted to allow major versions up to 7, you could run the command to generate a license file like so:
secure-electron-license-keys-cli --major "7"
If you wanted to allow major versions up to 7 and expire on 2022-12-31, you could run the command to generate a license file like so:
secure-electron-license-keys-cli --major "7" --expire "2022-12-31"
If you do run these commands, you will need to update your client page in order to compare against them, ie:
window.api.licenseKeys.onReceive(validateLicenseResponse, function (data) {
// If the license key/data is valid
if (data.success) {
if (data.appVersion.major <= data.major &&
new Date() <= Date.parse(data.expire)) {
// User is able to use app
} else {
// License has expired
}
} else {
// License isn't valid
}
});
The repository page has more details of options but this should give you the gist of what you'll have to do.
Limitations
This isn't perfect, but will likely handle 90% of your users. This doesn't protect against:
Someone decompiling your app and making their own license to use/removing license code entirely
Someone copying a license and giving it to another person
There's also the concern how to run this library if you are packaging multiple or automated .exes, since these license files need to be included in the source. I'll leave that up to the creativity of you to figure out.
Extra resources / disclaimers
I built all of the secure-electron-* repositories mentioned in this question, and I also maintain secure-electron-template which has the setup for license keys already pre-baked into the solution if you need something turn-key.
I am trying to decrypt paymentData property of PKPaymentToken object upon a successful Apple Pay authorization.
I am trying to follow the instruction here, but I am stuck on step 2 of the decryption steps, which says:
Use the value of the publicKeyHash key to determine which merchant
public key was used by Apple, and then retrieve the corresponding
merchant public key certificate and private key.
How do I do that?
Please advise.
Thanks!
Here's how to compute the publicKeyHash in Ruby, given the Apple Pay certificate file downloaded from the Apple Developer Center.
require "base64"
require "digest"
require "openssl"
# set cert_file = path to the downloaded Apple Pay .cer file
cert = OpenSSL::X509::Certificate.new(File.read(cert_file))
# strip off the "-----BEGIN PUBLIC KEY-----" line at the start of the string
pem = cert.public_key.to_pem.split("\n").drop(1)
# strip off the "-----END PUBLIC KEY-----" line at the end of the string
pem = pem.take(pem.length - 1)
decoded = Base64.decode64(pem.join)
public_key_hash = Digest::SHA256.base64digest(decoded)
The value of the publicKeyHash field is...a hash of your public key. As per the documentation, it's a SHA-256 hash of the X.509 encoded public key bytes of the merchant's certificate. You use this to determine which merchant identifier was used to sign the payment data (you probably only have one merchant identifier, in which case you'll already know which one is being used).