I am trying to use openssl for certificate chain verification using X509_verify_cert. I am getting all certificates- root certificate, intermediate certificate and child certificate which actually needs to be verified.
Using openssl I am able to convert certificate in X509 format.
X509_STORE_CTX *ctx;
ctx = X509_STORE_CTX_new();
X509_STORE *store = X509_STORE_new();
X509_STORE_CTX_init(ctx, store, certificateX509, ?);
int status = X509_verify_cert(ctx);
while reading documentation about X509_STORE_CTX_init and X509_verify_cert, we need to pass certificate chain at ? in the code. In the documentation, X509_STORE_CTX_init method is defined like this:
int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store,
X509 *x509, STACK_OF(X509) *chain);
# define STACK_OF(type) struct stack_st_##type
How to pass certificate chain if I have all certificates in X509 format?
Any code snippet may help more.
Thanks in advance!
This seems to work:-
STACK_OF(X509) *chain = sk_X509_new_null();
sk_X509_push(chain, x509);
X509_STORE_CTX_init(x509_ctx, x509_trusted, x509, chain);
sk_X509_pop_free(obj->chain, X509_free);
Related
I am trying to fetch some certficates from hashicorp vault using tf data source
This is how cert path looks like in vault
serverA:
dev-cert: <base64 encoded cert>
qa-cert: <base64 encoded cert>
test-cert: <base64 encoded cert>
This cert is used in other resource block which works fine as shown below
resource <somegcpresource> <xyz>
{
certificate = base64decode(data.vault_generic_secret.server_cryptoobjects.data["dev-cert"])
}
Can I use a custom env variable to fetch value of certificate like;
certificate = base64decode(data.vault_generic_secret.server_cryptoobjects.data["var.env-cert"])
or a local var to reference the key name from vault datasource like;
certificate = base64decode(data.vault_generic_secret.server_cryptoobjects.data[local.certname])
Yes, the data.vault_generic_secret.server_cryptoobjects.data is an object so you can access its values with their corresponding keys. If you declare a variable env-cert:
variable "env-cert" {
type = string
default = "dev-cert"
}
then you can use it as the key:
certificate = base64decode(data.vault_generic_secret.server_cryptoobjects.data["var.env-cert"])
Yes you can also use a local as the key:
locals {
certname = "dev-cert"
}
certificate = base64decode(data.vault_generic_secret.server_cryptoobjects.data[local.certname])
I would also suggest looking at the Vault PKI secrets engine for your overall use case if you have not already, since this example in the question is using the KV2 secrets engine.
I'm using IdentiyServer4 to generate tokens, I'm using the AddDeveloperSigningCredential() method to generate my RSA key with a KeyId.
But, in production, I'm using AddSigningCredential(CreateSigningCredential()), to generate a key like this :
private SigningCredentials CreateSigningCredential()
{
var signinkey = new RsaSecurityKey(RSA.Create());
signinkey.KeyId = "abcdefghijklmnopqrstuvwxyz";//How to generate KeyId ??
var credentials = new SigningCredentials(signinkey,
SecurityAlgorithms.RsaSha256);
return credentials;
}
How can I generate a KeyId? Can I set it to any arbitrary value?
You don't need to set the keyId and also creating the RSA key youself in code, sounds like bad practice. Then you can just as well use the AddDeveloperSigningCredential method.
You can actually look at the source for that method here to see how they do it in code:
https://github.com/DuendeSoftware/IdentityServer/blob/main/src/IdentityServer/Configuration/DependencyInjection/BuilderExtensions/Crypto.cs
But, in production you should generate the key externally and pass it in to IdentityServer, so the key is the same across redeployment/restarts. Otherwise previously issued tokens will not be valid anymore.
You can for example store the key in Azure Key Vault, or using some other configuration/secret system. Or in a database or as a file somewhere.
If you want to create one manually, using OpenSSL, then you can write
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -aes256 -out rsa-private-key.pem
I am using iTextSharp 5.5.13 in order to sign and validate PDF files. Few days ago I ended up with exception in OcspVerifier.Verify which stated "certificate expired on 20181225...GMT+00:00"
All PDF files are signed with embeded OCSP response and CLR. Validation was done using signing date and it used to work fine until the ocsp signers certificate expired.
Despite the fact that all certificates were valid at the time of signing, the OcspVerifier.Verify started to throw exception which states "cert expired...".
if (pkcs7.Ocsp != null)
ocsps.Add(pkcs7.Ocsp);
PdfOcspVerifier ocspVerifier = new PdfOcspVerifier(null, ocsps);
ocspVerifier.OnlineCheckingAllowed = false;
List<VerificationOK> verification = ocspVerifier.Verify(signCert, issuerCert, signDate.ToUniversalTime());
EXCEPTION: "certificate expired on 20181225...GMT+00:00"
It looks like bug to me? Is there any reason why OCSP signer certificate is not verified against signing date?
Class OscpVerifier - original, with line which validate cert against current date:
virtual public void IsValidResponse(BasicOcspResp ocspResp, X509Certificate issuerCert)
{
....
//check if lifetime of certificate is ok
responderCert.CheckValidity();
}
Modified version of OscpVerifier.cs:
// old definition with old functionality
virtual public void IsValidResponse(BasicOcspResp ocspResp, X509Certificate issuerCert)
{
IsValidResponse(ocspResp, issuerCert, DateTime.UtcNow);
}
// with signDate parameter:
virtual public void IsValidResponse(BasicOcspResp ocspResp, X509Certificate issuerCert, DateTime signDate)
{
...
//check if lifetime of certificate is ok
responderCert.CheckValidity(signDate);
//responderCert.CheckValidity();
}
with corresponding method call change fom:
virtual public bool Verify(BasicOcspResp ocspResp, X509Certificate signCert, X509Certificate issuerCert, DateTime signDate)
{
...
... {
// check if the OCSP response was genuine
IsValidResponse(ocspResp, issuerCert);
return true;
}
...
}
to:
virtual public bool Verify(BasicOcspResp ocspResp, X509Certificate signCert, X509Certificate issuerCert, DateTime signDate)
{
...
... {
// check if the OCSP response was genuine
IsValidResponse(ocspResp, issuerCert, signDate);
return true;
}
...
}
I included this variation of the OscpVerifier class directly in the project and it validates now old signatures as expected.
However, I am not sure if I hit the bug or there is reason why those signatures should be considered as not valid?
OCSP signer certificate must be validated at current time except if the OCSP response has been protected with a time stamp, so itext is working properly.
Summarizing, an OCSP response contains (See RFC6960 ):
target certificate and validity interfal
time when the response was generated
A digital signature of a CA trusted responder, and its certificate
The criteria for accepting an OCSP response is established in the RFC, but it does not clarify your question, because it does not establish how to validate the response over time.
3.2. Signed Response Acceptance Requirements
Prior to accepting a signed response for a particular certificate as
valid, OCSP clients SHALL confirm that:
The certificate identified in a received response corresponds to the certificate that was identified in the corresponding request;
The signature on the response is valid;
The identity of the signer matches the intended recipient of the request;
The signer is currently authorized to provide a response for the certificate in question;
The time at which the status being indicated is known to be correct (thisUpdate) is sufficiently recent;
When available, the time at or before which newer information will be available about the status of the certificate (nextUpdate) is greater than the current time.
However, it does indicate that the digital signature must be valid (2). In general, for a signature to be considered valid, it must comply with:
Cryptographic integrity
Validity of the certificate (expiration and revocation)
An OCSP response with an expired certificate will not meet the second criterion and therefore should be rejected. To extend the period in which a signature is valid, a time stamp must be added on the content. The PAdES standard specifies how
There is also an ETSI guide with the details on how to perform the verification of a PAdES and CAdES signatures, but unfortunately I have not found the link now
I need to register companies on my site for an electronic procurement system. Up to now these were local companies I could meet physically and give credentials to, but now they can be companies based anywhere in the world.
The solution is to have an online registration process whereby they submit a third party certificate. So say Verisign says they are 'Company X' so I register them as Company X and issue them credentials.
How can I implement this on my site? Do I simply give them a field in the registration form where they upload their certificate file? Do I then manually check these certificates in my back office? How does one check this manually? Is there a way to automate this process?
Once they have an account, should I simply request the credentials I issue them with to log in, or can all future logins request the same certificate file? In these a particular format for certificates I can request or should I allow a number of common formats that different certificate vendors provide?
Thanks in advance.
Being able to provide a certificate does unfortunately not prove anything. A certificate is completely public, and anyone can get a hold of the SSL certificate for any website. The certificate contains a public key. Proving ownership of the corresponding private key is what's required.
This is possible to do, but it requires that your users are technical enough to know how to run scripts and/or OpenSSL terminal commands so that they can sign something with their private key. Having the users upload their private key is of course a big no-no, as it means you can now act as the user, and that would require an enormous amount of trust in you to discard the private key after you've verified it.
From a technical perspective, you can do the verification by creating some kind of challenge, for example a random string, and have the user encrypt this string with their private key. If you decrypt this string with the public key in the certificate, and get the original string back, then you know that they have possession of the corresponding private key.
Here's a self-contained Ruby script that demonstrates this, with comments indicating which part of it is run on your side, and which part is run on their side.
require "openssl"
## This happens on the client side. They generate a private key and a certificate.
## This particular certificate is not signed by a CA - it is assumed that a CA
## signature check is already done elsewhere on the user cert.
user_keypair = OpenSSL::PKey::RSA.new(2048)
user_cert = OpenSSL::X509::Certificate.new
user_cert.not_before = Time.now
user_cert.subject = OpenSSL::X509::Name.new([
["C", "NO"],
["ST", "Oslo"],
["L", "Oslo"],
["CN", "August Lilleaas"]
])
user_cert.issuer = user_cert.subject
user_cert.not_after = Time.now + 1000000000 # 40 or so years
user_cert.public_key = user_keypair.public_key
user_cert.sign(user_keypair, OpenSSL::Digest::SHA256.new)
File.open("/tmp/user-cert.crt", "w+") do |f|
f.write user_cert.to_pem
end
## This happens on your side - generate a random phrase, and agree on a digest algorithm
random_phrase = "A small brown fox"
digest = OpenSSL::Digest::SHA256.new
## The client signs (encrypts a cheksum) the random phrase
signature = user_keypair.sign(digest, random_phrase)
## On your side, verify the signature using the user's certificate.
your_user_cert = OpenSSL::X509::Certificate.new(File.new("/tmp/user-cert.crt"))
puts your_user_cert.public_key.verify(digest, signature, random_phrase + "altered")
# => falase
puts your_user_cert.public_key.verify(digest, signature, random_phrase)
# => true
## On your side - attempting to verify with another public key/keypair fails
malicious_keypair = OpenSSL::PKey::RSA.new(2048)
puts malicious_keypair.public_key.verify(digest, signature, random_phrase)
Note that this script does not take into account the CA verification step - you also obviously want to verify that the user's certificate is verified by a CA, such as Verisign that you mentioned, because anyone can issue a certificate and hold a private key for foo.com - it's the CA signature of the certificate that provides authenticity guarantees.
I'm trying to perform the fingerprint of a TBSCertificate in order to sign it and insert it in a x509 certificate. I can't find any tool or library that allow me to do it separately.
I can create a x509 certificate and perform the signature like with openssl or many libraries but it will be included directly into the certificate, and I need to modify the signature before including it.
Do you know anyone?
I finally managed to do it using the pyasn1 library for python.
In case someone need it in the future, here you have a conversation in the pyasn1 mailing talking about it:
https://sourceforge.net/p/pyasn1/mailman/message/34523982/
and my personal solution:
from M2Crypto import X509, EC, EVP
from hashlib import sha256
from pyasn1_modules.rfc2314 import Signature
from pyasn1_modules.rfc2459 import Certificate
from pyasn1.codec.der import encoder, decoder
csr = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNyakNDQVpZQ0FRQXdEUVlKS29aSWh2Y05BUUVMQlFBd2dZWXhDekFKQmdOVkJBWVRBa05VTVJJd0VBWUQKVlFRSURBbENZWEpqWld4dmJtRXhFekFSQmdOVkJBY01Da0psYkd4aGRHVnljbUV4RVRBUEJnTlZCQW9NQ0ZCaAplVk5sYm5ObE1Rd3dDZ1lEVlFRTERBTkJRMEV4RERBS0JnTlZCQU1NQTBGRFFURWZNQjBHQ1NxR1NJYjNEUUVKCkFSWVFZV05oUUdSbGFXTXVkV0ZpTG1OaGREQWVGdzB4TlRFd01EZ3dPVFF4TURKYUZ3MHhOakV3TURjd09UUXgKTURKYU1JR0FNUXN3Q1FZRFZRUUdFd0pEVkRFU01CQUdBMVVFQ0F3SlFtRnlZMlZzYjI1aE1STXdFUVlEVlFRSApEQXBDWld4c1lYUmxjbkpoTVF3d0NnWURWUVFLREFOVlFVSXhEVEFMQmdOVkJBc01CRVJGU1VNeEt6QXBCZ05WCkJBTU1JbTF0VjFGVlFsbFpWMVJ2V2xwTmNIYzBjR0ZXVG5NeVRXNXZTbE5oUlZkUmVua3dWakFRQmdjcWhrak8KUFFJQkJnVXJnUVFBQ2dOQ0FBUjVJTWU2aDJwUlpwM201b25VcWloeGwyNkFIQjhMR01WZCtMWUNFTUl4V2U1ZQpySVJmcDA5bHNPUjB3L1B3T3N0bzRXSWFYOXFPSnBTb2JwZFlYRnJaTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCCkFRQXdHZVl3bkM5MmErR1g3VXE4N1k5Z3hXdFVKUWZiUlRwbXdCV1NPdmNlS3Z2Ky9zV3o5VFRqSGRKbElqVnYKbkQ5RHY5aHVlQUVONkE3Sm43SE80ZDhwelJ2d3pQSU5peXN4TUlzaWsxbldpTTRieTBLSDh4bE5SZEFoc3ZZTApVQ3hLSXVGMm1sUytJRGVtMUQyZE96L3ZFZlcrZVE4NVhsSVRycExpMFZlY3d5NnhwejNMN2R2SEdTOFJ1aVlyCkxkS1J3VnVGYmI4QmRHdVJ3dHgwNCtEeGJFKzlUb3hHSmFiM1VaV1loV3ByekcyS2owV0pORW44UlBwWXJjb2sKY3lBSTh4OFh0TDUrZUs5aklpV1NlcHIzcU9Zc3V6V2NqZ2VIeUdCUHNqN1lRQ2ZuWVFTbHBJMzJHRnZ5YWRmTApmRmZXSExxZE9nQmVET2JwenlaVDlyazkKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=="
cert = X509.load_cert_string(b64decode(csr))
ca_pkey = EVP.load_key(ACA_KEY)
asn1_cert = decoder.decode(cert.as_der(), asn1Spec=Certificate())[0]
tbs = asn1_cert.getComponentByName("tbsCertificate")
tbs_der = encoder.encode(tbs)
digest = sha256()
digest.update(tbs_der)
signature = ca_pkey.get_rsa().sign(digest.digest(), "sha256")
# Take the raw signature and turn it into a BitString representations (special thanks to Alex <ralienpp#gmail.com>)
bin_signature = Signature("'%s'H" % ''.join("%02X" % ord(c) for c in signature))
asn1_cert.setComponentByName("signatureValue", bin_signature)
# Check that both certificates matches
cert.sign(ca_pkey, md='sha256')
print cert.as_text()
print encoder.encode(asn1_cert) == cert.as_der()
The initial csr is a base64 encoded X509 Certificate in BER.
Is important to stress the csr already contains the proper Signature Algorithm.