In some reason I need to extract public and private keys from Apple p8 certificate. Any idea how?
Mmm, no but I can lead you through it quickly; the p8 file is not private key, it's both keys together (somehow) actually, so to get both private and public keys out of it, on my local machine I let VaporAPNS load the p8 file and added a breakpoint to VaporAPNS/Options.swift:69, then in priv variable, you'll see private part of the key, in pub, you'll see public part of the key
Related
Confused on how to do certificate pinning. How do we instll the certificate in n android or ios device through xmarin forms. Is this done during installation if application? There are some tutorils on how to use validation of https requests using pinning but nothing bout installation of the public certificate?
Another way to go is to perform pinning on the leaf's certificate public key and in this simple demo class we can see how to do it when using the HttpClient by customizing the ServicePointManager:
using System;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
namespace ApproovSDK
{
/**
* Service point configuration.
*
* Adds simple pinning scheme to service point manager.
*
* FOR DEMONSTRATION PURPOSES ONLY
*/
public static class ServicePointConfiguration
{
private static string PinnedPublicKey = null;
public static void SetUp(string key = null)
{
PinnedPublicKey = key;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
ServicePointManager.ServerCertificateValidationCallback = ValidateServerCertficate;
}
private static bool ValidateServerCertficate(
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors
)
{
if (PinnedPublicKey == null || PinnedPublicKey.Length <= 0) return true;
//Console.WriteLine("Expected: " + PinnedPublicKey);
//Console.WriteLine("Found : " + certificate?.GetPublicKeyString());
return String.Equals(PinnedPublicKey, certificate?.GetPublicKeyString(),
StringComparison.OrdinalIgnoreCase);
}
}
}
The above example was written for demo purpose and a better implementation should associate multiple keys for each domain being called.
While you can use the certificate itself in order to perform your validation and thus pin the certificate there are alternative options.
As per the OWASP documentation here you can implement any of the following 3 approaches:
Certificate
The certificate is easiest to pin. You can fetch the
certificate out of band for the website, have the IT folks email your
company certificate to you, use openssl s_client to retrieve the
certificate etc. When the certificate expires, you would update your
application. Assuming your application has no bugs or security
defects, the application would be updated every year or two. At
runtime, you retrieve the website or server's certificate in the
callback. Within the callback, you compare the retrieved certificate
with the certificate embedded within the program. If the comparison
fails, then fail the method or function.
There is a downside to pinning a certificate. If the site rotates its
certificate on a regular basis, then your application would need to be
updated regularly. For example, Google rotates its certificates, so
you will need to update your application about once a month (if it
depended on Google services). Even though Google rotates its
certificates, the underlying public keys (within the certificate)
remain static.
Public Key
Public key pinning is more flexible but a little trickier due to the
extra steps necessary to extract the public key from a certificate. As
with a certificate, the program checks the extracted public key with
its embedded copy of the public key. There are two downsides two
public key pinning. First, its harder to work with keys (versus
certificates) since you usually must extract the key from the
certificate. Extraction is a minor inconvenience in Java and .Net,
buts its uncomfortable in Cocoa/CocoaTouch and OpenSSL. Second, the
key is static and may violate key rotation policies.
Hashing
While the three choices above used DER encoding, its also acceptable
to use a hash of the information (or other transforms). In fact, the
original sample programs were written using digested certificates and
public keys. The samples were changed to allow a programmer to inspect
the objects with tools like dumpasn1 and other ASN.1 decoders.
Hashing also provides three additional benefits. First, hashing allows
you to anonymize a certificate or public key. This might be important
if you application is concerned about leaking information during
decompilation and re-engineering.
Second, a digested certificate fingerprint is often available as a
native API for many libraries, so its convenient to use.
Finally, an organization might want to supply a reserve (or back-up)
identity in case the primary identity is compromised. Hashing ensures
your adversaries do not see the reserved certificate or public key in
advance of its use. In fact, Google's IETF draft websec-key-pinning
uses the technique.
I would strongly recommend using the Hashing approach meaning that when you validate the certificate coming in you just need to check that the hash of the certificate coming from the server is the one(s) that you expect. Something like the following:
private bool ValidateServerCertificate(object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
// Make sure we have a certificate to check.
if (certificate == null)
{
return false;
}
if (sslPolicyErrors != SslPolicyErrors.None)
{
return false;
}
return this.KnownKeys.Contains(certificate.GetCertHashString(),
StringComparer.Ordinal);
}
Where KnownKeys is a simple compile time defined array of your known certificate hashes:
private readonly string[] KnownKeys = new[]
{
"INSERT HASH",
"AND A SECOND IF REQUIRED"
};
I'm using Net::SSH to automate access to remove hosts from a ruby program, using key authentication. The program does not dictate where the user should put the private key, instead relying on the user's SSH agent to provide the required keys (as it should).
The problem is if the required private key is not available, the connection will fail - and this may happen a long way into the program (the SSH connection is one of the last things we do after doing a lot of other - not easily reversible - operations).
Supposed that I know what private key the user should have (as specified by the key fingerprint), how can I do this check from ruby - other then execute ssh-add -l and grepping the output?
I've looked at Net::SSH KeyFactory class, but it only lets you load private keys if you know the name of the file in which they are stored.
I figured it out - Net::SSH::Authentication::KeyManager has what I need:
hasidentity = false
Net::SSH::Authentication::KeyManager.new(nil?).each_identity do |i|
hasidentity |= i.fingerprint == 'my:ke:ys:fi:ng:er:pr:in:t'
end
KeyManager also has a collection called identities, though from what I understand, that holds only keys loaded directly into Net::SSH, while each_identity iterates over all available identities, including those available from an agent.
I recently came across a situation where I absolutely needed to use the method OpenSSL::PKey::RSA#params. However, the doc says the following:
THIS METHOD IS INSECURE, PRIVATE INFORMATION CAN LEAK OUT!!!
...
Don’t use :-)) (It’s up to you)
What does this mean? How is the private key normally protected within the instance of the RSA key and how is this different from any regular object?
Can I prevent information from leaking by doing something like this, where the method is only accessed within a lambda:
private_key = OpenSSL::PKey::RSA.generate(2048)
save_private = lambda do
key = OpenSSL::Digest::SHA512.new.digest("password")
aes = OpenSSL::Cipher.new("AES-256-CFB")
iv = OpenSSL::Random.random_bytes(aes.iv_len)
aes.encrypt
aes.key, aes.iv = key, iv
aes.update(private_key.params.to_s) + aes.final
end
private_enc, save_private = save_private.call, nil
Also, if this security problem has anything to do with variables lingering in memory awaiting GC, can forcing garbage collection make things more secure?
GC.start
Thanks in advance to anybody who can clear this up.
It seems to give away information of the private key. The key components need to be available to perform any signing operation or decryption so normally the key information is in memory in the clear. Obviously if you retrieve it you must make sure that you keep it safe. I presume that this is where the warning comes in.
You can do all kinds of things like encrypting the private key parameters, but then you get to a point where you have to store the decryption key. Basically this will end up being impossible to solve without an external system (or a person keeping a password).
I need to export public and private RSA key from certificate, stored in PKCS#12 format, on Windows.
I can open certificate store with CertOpenStore(), then find certificate with CertFindCertificateInStore() and acquire private key with CryptAcquireCertificatePrivateKey().
It works Ok. Then I extract user key with CryptGetUserKey() It works too.
But CryptExportKey() with blob type PRIVATEKEYBLOB fails.
CryptSetKeyParam() with KP_PERMISSIONS and set permission CRYPT_EXPORT also fails.
How could I get all RSA key pair parameters in such case?
All examples use CryptGenKey() to create and THEN export key, but I need to export existing key pair to simple binary form.
Found solution: if use more specific PFXImportCertStore() to open PKCS#12 file instead of generic CertOpenStore() with CERT_STORE_PROV_PKCS12 store provider, it accepts flag CRYPT_EXPORTABLE and key could be exported with CryptExportKey().
I´ve got a User model like this one
#Entity
#Table(name="SHOPPER")
public class User extends GenericModel {
#Id
#Column(name="SHRFNBR")
#GeneratedValue(generator="SEQ_SHP", strategy=GenerationType.SEQUENCE)
#SequenceGenerator(name="SEQ_SHP", sequenceName="SEQ_SHP", allocationSize=1)
public Long id;
#Column(name="SHLOGID")
public String email;
#Column(name="SHLPSWD")
public String password;
public static User isUser(String user, String pass){
return User.find("byEmailAndPassword", user, pass).first();
}
}
On DB password its RAW type and on Controller it´s encoded with RSA.
The main thing it´s that it doesn't find any result because the binary that goes into the DB seems different than the one that's on the field.
At first I thought it could be some character encoding issue on the Application but then I pointed to the same DB but on production and it worked. So I checked the Devel DB and found another Characterset instead of ISO-8859-1 (prod) was ISO-8859-15 (devel) that seems little different.
After updating the devel characterset the situation it´s the same. Is there any other place where the RSA string is getting wrong encoded on DB?
Process description:
The process is a login process where the user inserts email and password, the last one gets encoded with RSA and the result it´s sent to DB for comparison.
The field on DB contains a value like this one:
CB4F3ECB7763C98EF67CA761700D1FB255F90E4473B1BB594B2238756307DF2D155D57A2CBA2930C162CB0634765D48EA111F743F6825F2457340148F680E300
More info:
DB Oracle 10g
Play Framework 1.2.4
Don't map binary data to a String, use byte[] instead, this way you won't have any character encoding issues.