We sell a product that sets up several web services, each serving on a bunch of endpoints, some of them even supporting arbitrary sub-FQDNs. With this I mean that if the endpoint is foo.example.com, then it also serves *.foo.example.com.
Anyways, one of the features we want to provide is the ability of accepting any bunch of certificates and private keys, sort them by endpoint, validate them and push them to the different services. This means that we can accept anything between a single file with a cert covering all the endpoints ans SANs and its private key and the whole chain up to the CA root; and a bunch of files containing anything and figure out whether they're certs, what kind, where they do apply, etc. We decided to do this because certs are hard enough already, so we want to remove the onus of doing all this from the client.
The way we're doing this is as follows: For each endpoint, we find a cert that covers it. Then we find the key that matches and the chain back to the top.
My issue is with the last part of that last part. We consider we found the top of the chain when we find a self signed certificate with the CA bit on. Imagine my surprise when yesterday a colleague handed me a root cert with this:
Issuer: O = Digital Signature Trust Co., CN = DST Root CA X3
Subject: C = US, O = Internet Security Research Group, CN = ISRG Root X1
That's Let's Encrypt root cert not being self signed but signed by someone else. Is this OK?
The only hint to a solution comes later when I find in the cert:
Authority Information Access:
CA Issuers - URI:http://apps.identrust.com/roots/dstrootcax3.p7c
Should I (automatically) download that file to complete the chain building? Or should I search for the C = US, O = Internet Security Research Group, CN = ISRG Root X1 cert in the system's trusted roots? Notice that because our product can be installed in dark sites, the former is not really an option.
The answer is rather complex, I'll try to make a bullet list:
When validating a chain, always use a trust store first. For instance, recent Linuxes have one somewhere in /etc/ssl. This means that if you like me are backtracking from the final cert, you should look for Issuers first in the trust store, then in the (untrusted) provided chain, otherwise you end up with the same bug openssl-1.0.2 has.
Once validated this way, provide the original chain for maximum compatibility. This is because the original LE chain's 'root' cert is either replaced with the new (since 2015!) LE self-signed root with the previous algorithm, or it is validated with the missing 'real' root that has expired last year. This seems to be the case with very old Android systems (hence the reason LE provides this chain by default in the first place).
You can always ask LE for a newer chain with the SS root cert, but as stated above, this is less compatible. If you can live without pre-2015 clients, it's probably the best way.
Related
let us assume, we have a valid HCERTSTORE handle of opened certificate store. How can we determine - is opened store physical or system?
Restriction 1 - we should use CryptoAPI (C++) only.
Restriction 2 - we've successfully forgotten, what kind of store was used in CertOpenStore() call.
I don't see a way to solve this with CryptoAPI and, as the constraint 2 is artificial, don't think it was designed to address this problem. Closeable handles can't be passed around between processes, so one cannot "forget" what it was unless deliberately: the knowledge is right there, in the code that got the handle.
By looking through the function list in the left pane at CertOpenStore - MSDN, I see CertGetStoreProperty(), but there's only one predefined property, CERT_STORE_LOCALIZED_NAME_PROP_ID, which isn't reliable.
First, some info on our system, which is basically an eTendering solution for the construction industry.
So:
List item
Our system has multiple companies
Each company has multiple users
Each company can create multiple auctions
Other companies can then submit their bids for the available auctions. A bid consists of hundreds or thousands of individual items, and we would just need to encrypt the 'price' section of these records.
The problem that we're facing is that our large customers do not want us to ever have access to the bid prices, at least while the bidding is in progress, which is totally understandable. Right now, we are simply encrypting the prices via a symmetric encryption, so even though the prices are effectively encrypted in the database, their concern is that we have the key to decrypt the prices.
We're thus looking at some form of public key encryption system.
Here is our initial thoughts on the solution:
When a company signs up, we create a public/private keypair using OpenSSL for it and we save it in S3 or straight into the database. For this to be really useful, we would enforce the user to use a strong password for the private key, which would of course not be saved in the database.
When a company submits a bid for an auction, we encrypt the prices using the public key of the auction's owner company and we save them into the database.
When the auction bidding period is over and the issuing company wants to generate the report the first time, we ask him to input his password and use that along with his company's private key to decrypt the prices.
To make subsequent traffic faster, we cache the decrypted data (and maybe encrypt it using a simple symetrical encryption system)
So here are the questions (and we're unfortunately not security experts, so sorry if those are stupid questions):
Does this make any sense or is it a totally ludicrous or overkill solution?
Would we generate the keys using OpenSSL, OpenPGP or another solution?
What happens if a user wants to change his password or generate a new key? Would there be no other way but to decrypt/re-encode everything with the new key?
What would some of the pitfalls be with this solution?
Are there any better solutions that you could recommend?
So here's my suggestion, if you want to solve this using encryption...
Each user and each company should generate OpenPGP (or GnuPG) asymmetric public/private key pairs
Each of those public keys should be uploaded to a public key server
Companies could optionally "sign" the public keys of the individual users, to designate a trust relationship with those users (and revoke that signature if that relationship changes)
The auctioneer or non-partisan arbiter would also generate a key pair and push that public key to the public key server
As part of an auction registration process, each user would import the public key of the auctioneer, and the auctioneer would import the public key of each user
A trusted third party, perhaps a SaaS vendor outside of the auctioneer, would host a service through which users and the auctioneer would communicate
Bidding users would create a bid by
signing their bid with their private key
encrypting their proposed price to two keys: their own public key and the auctioneer's public key
submitting their bid to the trusted third party service, which would need to enforce an embargo on any user retrieving bids before the auction expiration
At auction end, and only after auction end, the auctioneer retrieves all of the bids, decrypts them, and verifies signatures
A couple of key points:
It's essential that no user or company private keys are ever shared or stored within the service -- that's the only real "flaw" I see in your proposed methodology in your question. If that's the case, it would be very possible for one user to accuse an administrator of "fraud" or "tampering" with bids, as an administrator of your server would ultimately have access to the private keys of all users, since you've generated them yourself.
Along those same lines, it's essential that any an all communication and "bids" are cryptographically "signed" with the truly private keys by each user. This is how you would know that a bid came from one particular user and only that user, and that the bid could not have been tampered with.
Encrypting the bids to the public keys of the bidding user and the auctioneer ensures that the third party SaaS vendor has no introspection into the bids themselves during the blackout period while the auction is open. I believe this is the most important point to solving your problem as described.
Note that it might actually be preferred to encrypt each bid to a ring of all of the bidding users, if by design you want to make all bids public after the auction is closed. That would be a slight modification to my algorithm as described above.
In the interest of full disclosure and perhaps some subtle marketing, I happen to be the architect and CTO of a company called Gazzang who has implemented a product called zTrustee which operates exactly as described above ;-)
To be clear: I have a hunch that your clients are probably not willing to sacrifice all of the conveniences that come with having your system manage some of the cryptography; you should probably present several options and their weaknesses vs convenience.
General Points
Before anything else, you start start with an explicit threat model, covering every possible attack you can think of. Even if you choose not to address some of the attacks (it's unrealistic to handle everything), you'll ferret out the more obvious attacks, and have at least a basic set of steps for handling others should they occur.
Re: Does this make any sense?
I think the general premise, while overkill on the part of your customers, makes sense from a security perspective. Your clients want a cryptographically secure system; fair enough.
However, some points on your proposed solution:
By allowing the client to pass their password over the wire, an attacker (which your client seems to think could be you) needs to only man in the middle that password to gain access to the pricing data.
SSL helps mitigate this, but an errant log line somewhere along the line could very well expose the client's password by accident.
The only truly cryptographically secure way (as I see it) for the client to ensure that you don't have access to the pricing data is for them to encrypt it, and your system just acts as a broker for the encrypted data. This, in effect, makes you a broker of encrypted packets and public keys, but your system should never see private keys.
The question is: are clients willing to manage their own keys, or is that too burdensome to them? You might be able to automate most of it, at least (client app/website would handle storing the private key locally, and would also be responsible for gathering public keys of the other interested parties in order to decrypt their encrypted bids)
Re: Would we generate the keys using OpenSSL, OpenPGP, or another solution?
Really doesn't matter all that much; each of those options just define the container format for the public/private keys and any metadata. Use whichever one fits your language/platform best.
The main decision point should be in which encryption algorithm and key strength: RSA-2048? RSA-4096? elliptic curve? something else?
Specific to Ruby: You're probably just going to want to use the OpenSSL library, since it's part of the standard library. But to reiterate my point above: It's even better if your servers never even see the private keys (if the clients are ok with the trade off of better security over convenience)
Re: What happens if a user wants to change his password or generate a new key?
Changing a password is trivial: the private key its self is just encrypted w/ some symmetric algorithm. Changing the password involves decrypting the existing key, and re-encrypting it with the new key. If the client were to lose their password, there is no recovery.
Generating a new key is probably safer, but requires more diligence on your part (encrypted payloads will need to identify which key they match, and clients could have multiple keys active at a time). This is a good thing, though; it is a common practice to rotate keys regularly, even if they are not compromised.
When a company signs up, we create a public/private keypair using OpenSSL for it and we save it in S3 or straight into the database. For this to be really useful, we would enforce the user to use a strong password for the private key, which would of course not be saved in the database.
I am a bit sceptical about this step. If you (the developer company) generate both the public and the private key used for the encryption it means you are 50% into being able to break the encryption. The only thing that protects your customer is the password, which you might be able to bruteforce (i am not suggesting that you will but you have the ability to do so)
If you will use PKI (or what you have described) you need to ensure that the key creation does not happen on your system. The client should create the pair on their systems and then provide you with their publoic key which you will use to encrypt the prices. The client then will be able to decrypt using the private key on which they have sole control
What would some of the pitfalls be with this solution?
The pitfall is that you are making a complex solution. Especially if you follow my advice above, then you place your trust on the customer to not "lose" the private key (and/or password) or else they won't be able to decrypt the prices. In addition, if the key leaks from their side, it's difficult to prove that your application is "innocent"
Would we generate the keys using OpenSSL, OpenPGP or another solution?
In order to prevent the pitfall of a customer losing a key, you might want to look into PGP (the commercial version does this for sure) and into the concept of ADK (additional decryption key) and "split keys". The idea is that besides encrypting with the public key of the customer you also encrypt with a "corporate" key which can only be used if y out of x number of people come together (as an example, 10 people can possess parts of the key and if 6 of them come together they can reconstruct the key). The parts can be shared amongst your company, the client, their lawyer, etc
I'm developing an application that on one side produces a code with certain information about a purchase, wich includes a credit information. For example, you could buy a given number of minutes to spend in a public PC on a cybercafe, and you receive a ticket with a number/code with that ammount of minutes, which is then decoded and processed by the PC blocking software in the public PC.
The full length of that information (including date of purchase, an ID, and so on) is about 12 bytes. I need to secure that data, obviously, as much as i need to make it unalterable.
I don't have experience on cryptography but have been reading a lot the last few days, so i came up with an scheme in which i encrypt the data using Twofish in CFB mode (to keep the ciphertext small), and add a 4 bytes long IV, randomly generated. I realize it's a short IV, but the reasoning behind is that an attacker should grab an apparently ridiculous ammount of tickets to become a thread with an IV of 65535 variations.
The problem i see (let alone the ones i miss) is that i also need to authenticate the code, since in CFB mode, a small change in the ciphertext produces just a small change in the plaintext, so anybody could change, for instance, its ticket's credit by just changing an A for a B.
So, first question is: is there any obvious problem in using the CRC16 of the plaintext as IV, and add it (unencrypted) to the encrypted code to use it both for authentication and IV? I repeat i'm not in cryptography, but it 'feels' odd to put some information about the plaintext unencrypted along with the cyphertext. But is just the gut feeling.
Or, instead, should i use a stream cipher? Which one could make a big change (/mess up) the plaintext from a small change in ciphertext. Is this related to the error propagation property in the cipher mode of operation?
Some guide, please?
Thanks a lot.
By the way, if that matters, im using mcrypt on PHP.
I must add that the other end of the app, the one that reads the ticket, is not (and cannot be) online. Sorry for that ommision.
It sounds like what you are looking for is either an HMAC or, if you cannot secure the client PCs, a digital signature, not encryption.
I would add some salt and produce an MD5 hash, delivered right with the plaintext
Is there a cryptographic mechanism by which it is possible to sign a document with a date, such that it is not possible to forge that same signature at a later date? Maybe some sort of server that publishes daily cryptographic keys (but how can you trust them? ;-).
For the inevitable prodding pragmatists, I'm not trying to accomplish some task. I'm just curious what the solution space is like.
This is called Timestamping (TSP protocol, RFC 3161). Different digital signature standards (PDF and XML signatures, CAdES, PAdES, XAdES) include support for advanced timestamping based on TSP.
MS Authenticode also includes timestamping, but uses different (incompatible and less secure) mechanism for it.
TSP alone (without signature protocols) is not used a lot, but in conjunction with signature standards it becomes very handy.
GuardTime has an interesting service, where the timestamp does not depend on a trusted third party ("signed time") but can be independently verified by any interested party. It works somewhat similarly as Bitcoins, based on hash trees.
I'm writing CSP library (for CryptoAPI) for smartcards my company sells.
I have question about difference between AT_SIGNATURE key type and CALG_RSA_SIGN algorithm for private key (the same also for AT_KEYEXCHANGE and CALG_RSA_KEYX).
I know what is written on MSDN site, but how specifically CSP DLL should work if either of CALG_RSA... algorithms is specified in call for CPGenKey() function? I mean should it generate session RSA private key or the key should be generated and saved on card? Or maybe it depends on flags specified on CPAcquireContext() call (CRYPT_VERIFY_CONTEXT ie.) and AT_SIGNATURE should be defined as "default algorithm for signature", which for our cards is RSA?
Thanks
It's not my answer, just found a good explanation on the Internet:
AT_SIGNATURE key acn ONLY be used to sign a message. It cannot be used to
wrap (export) session key. AT_KEYEXCHANGE key can be used for BOTH purposes.
So if you want to use only 1 (one) key pair for both, you definitely need
AT_KEYEXCHANGE key pair.
You also need to understand some security implications - and why using two
keys are better than using the same key pair for both:
Normally you should NEVER reveal your signing private key. If it is lost, you
simply generate a new signing key pair and use that from that point of time.
On the other hand, you normally need to back up your key exchange key,
because without that you cannot decrypt messages in the future (if the
private key is lost). However, backup means that the key may be available to
someone else - who now could sign messages purportedly coming from you - and
you wouldn't want that.
If you use different key pairs for the two actions you can have secure
signing (your signing private key never goes out) and still can back up your
key exchange key.
One more note on generating these keys:
Since you don't want your signing key know, when you generate it with
CryptGenKey(AT_SIGNATURE) you should never set flags KEY_EXPORTABLE or
KEY_ARCHIVABLE and you may want the extra protection and add
CRYPT_USER_PROTECTED, so every time the signing key is used the user knows it.
On the other hand, when generating the key exchange key using
CryptGenKey(AT_KEYEXCHANGE) you should immediately back it up: set the flag
CRYPT_ARCHIVABLE and IMMEDIATELY export the key for backup. (This flag allows
to export the key only once - right after it is created -, so it is more
secure than allowing to be exported any time by setting CRYPT_EXPORTABLE.)
Laszlo Elteto
SafeNet, Inc.