Asymmetric Cryptography - ashishranjandev/developer-wiki GitHub Wiki

Introducing the Public Key Infrastructure The Public Key Infrastructure Asymmetric cryptography is also called public key cryptography.
We use public and private keys in cryptographic and signature operations.
Those keys, and the public key certificate, are born out of an implementation of the public key infrastructure.
So it's worth taking a bit of time to look at PKI.
We're going to start off by taking a look at the role that trust plays in a PKI and the responsibilities of a CA to safeguard that trust.
I'll give you a brief idea of what certificate authorities are, followed up by a look at root, intermediate, and policy CAs.
We'll get into how key pairs are used in cryptographic and signing operations.
And finally, we'll look at the workflow involved with issuing and revoking certificates.

PKI Trust and Responsibilities You're going to hear me talk a lot about trust in this course, and that's because asymmetric cryptography, which is facilitated by an implementation of a public key infrastructure, is designed to be used in an unsecure network to securely and privately exchange data.
At the core of this trust model is the certification authority.
And the certification authority investigates and confirms the identity of an entity before issuing a certificate to them.
We, in turn, then put our trust into the certification authority by trusting the root certificate.
And more on this later.
And before we keep going here, I want to mention that I refer to a CA as both a certificate authority and a certification authority throughout the course.
So please don't let that throw you.
But depending on the context, a CA can mean different things.
A CA can be an overall organization like Verisign or Entrust or any number of the other providers out there.
It also refers to the logical machines that perform different functions in the overall process of issuing public key certificates.
For example, there are root certificate authorities, intermediate certificate authorities, and policy certificate authorities, among others out there.
But getting back to our discussion of PKI here, the public key infrastructure, which, again, supports asymmetric cryptography, has four major responsibilities.
The first one we're going to look at is authentication, which is are they who they say they are? And there are a couple of ways that this happens.
The first is that we look at the identity information in a certificate that has ultimately been signed by a trusted CA.
But in a more passive sense, by validating the signature of data using the public key attached to a certificate, that we trust, we can verify that the signed data sent to us is legit.
Next we have integrity, which is is this a valid message, and is it the same message that was sent to us? Meaning that we want to be sure that the data has not been altered in root.
And this is where signing and verifying data comes into play.
Signatures are basically a cryptographic hash function that calculates the hash value for the data being sent.
So by using the sender's public key, we can verify that they are the one who sent it and make sure that the data wasn't altered in root by using the hash value.
If the data was altered in root, then the hash function won't match and we'll know that we can't trust them.
So the next responsibility here is confidentiality, and this one's pretty straightforward.
You know, it's only the people who we want to see the message can see the message.
And anyone else just can't read it.
And this, of course, is done with encryption.
The last one here is non-repudiation, which is a bit of an outlier, and I say it's a bit of an outlier because the other responsibilities are used to maintain trust in an unsecured network.
Non-repudiation, on the other hand, is used in situations where there's a lack of trust, when it becomes necessary to hold an entity accountable as the origin of data.
And typically you'll see this in legal situations.

Certificate Authorities Overview In the last little segment there, I mentioned that there are different types of certificate authorities.
From here on out I'll be talking about the machine CAs rather than the organization CA.
And the CAs have a common function, which is that they all sign certificate requests.
But beyond that they serve different purposes.
So when I talk about signing, a real world analogy would be notarizing a document.
In the United States, notarizing a document means that a person called a notary public has verified the identity of the person or people signing the document, witnesses them signing the document, and then stamps their seal on the document.
Depending on the needs and fundamental purpose of a given PKI implementation, we may see any or all of the different types of certificate authorities in use.
There is one type that we're about to look at which will always be there, and that is the root certificate authority.

The Root CA The root CA is at the top of the hierarchy and there's only one instance of it.
Also, it usually does not sign end user certificates itself.
Instead, it will sign certificates for the next tier of CA instances.
In turn, these CAs might sign end user certs or they might sign certificates for CAs at the next tier down, depending on the size and complexity of the PKI implementation.
There are a couple of attributes of the root CA certificate that I want to mention.
First, it's at the top of the CA hierarchy, which means that there isn't anyone to sign that certificate compared to those CAs below it whose certificates are signed.
So the root CA certificate is self-signed.
The other attribute of a root CA certificate is that it's identified as a CA certificate using the Basic Constraints extension.
And I get into detail about certificate extensions in the x.
509 certificates module, but this extension is basically a binary value used to mark whether or not a certificate belongs to the root CA.
And also, only the root CA certificate will be marked as a CA certificate.
Other CA types will have signatory authority, but are not marked as a CA certificate.
So what stops me from creating my own CA certificate, distributing it, and wrecking havoc? Well nothing stops you from creating your own CA certificate, but as far as wrecking havoc goes, any certificate that you generate will not be trusted.
In order for a certificate chain to be trusted, the root certificate authority certificate must be trusted.
Just because it's a root CA doesn't mean that it's automatically trusted.
Later on in the course, you'll hear me use the phrase actively trust a root CA certificate.
And what I mean by this is that when we receive a certificate that has been signed by a CA, we trust that certificate if we trust the cert that signed it.
The root CA certificate is self-signed though, so how do we know if we can trust it? Well the answer is that we explicitly assign trust to it.
Operating systems typically ship with a set of root CA certificates that have been marked as trusted.
In Windows, for example, you can see these certificates via the certificate manager.
If we have a certificate that we trust that's not part of the store, actively trusting the certificate would be placing it into the certificate store and marking it as trusted or loading it into our software and marking it as trusted.
You'll usually find that a root CA is kept offline, except when assigning intermediate CA certificates.
And it's kept offline because, if you think about it, the private key of a CA is the identity of the CA.
If some other entity gets their hands on the private key, the CA becomes untrustworthy, and this means that at best it has to generate new keys and reissue every active certificate that it has issued, but since CAs are in the business of trust, the repercussions of losing the key could be much more severe.
By signing the set of certificates for CAs down the hierarchy, those certificates inherit the trustworthiness of the root CA when they sign certificates, but if one of those keys is compromised, the damage is less severe.

The Intermediate CA There are a few names and definitions for certificate authorities in the overall CA hierarchy.
And we've talked about the root CA, which is at the top of the hierarchy.
Now depending on where you're looking, you'll find different definitions for CAs that live underneath the root CA.
They might be subordinate CAs, intermediate CAs, policy CAs, issuing CAs, probably a few others.
What's important to us in this course is having a public key signed and being able to validate a certificate.
And, of course, the validated certificate we need to be able to walk up the certificate chain, if you will, to the root CA.
Now conceptually, a subordinate CA and an intermediate CA are the same thing for our purposes.
So I'll be talking about intermediate CAs.
We're also going to use intermediate CAs to issue certificates.
So why do we have a CA hierarchy? I mean there's a cost of maintaining multiple CAs in terms of time, money, and complexity.
So what's the benefit? Well, there are a couple of reasons.
The first one is organization.
Having intermediate CAs gives you the ability to separate concerns, meaning that we can designate a specific intermediate to handle specific types of certificates or cover a specific geographic region.
In the writing the code module, we're going to design the trust us certificate authority, which provides certs for customers around the world.
Part of this design is intermediate CAs in different parts of the world to handle different geographic areas.
The other and more important reason is risk mitigation.
What happens if a certificate authority is compromised? Well, the certificate authority certificate has to be revoked and the new one issued.
Big deal, right? Well it is a big deal because not only does the CA certificate have to be revoked and reissued, but so does every certificate that it signed.
And any certificates that were granted authority on its behalf also have to be revoked and reissued.
If we have a single root CA, then every single valid certificate that the CA has issued has to be revoked and reissued.
Not only that, but the new CA cert would have to be reinstalled to all operating systems, applications, browsers, devices, consoles, email clients, on and on.
That's not to say that an intermediate CA breach would be easy to deal with, but by comparison is a lot less of an impact.
And, again, we'll be looking at creating intermediate CAs in the writing the code module.

The Policy CA When we get a public key certificate, we might want to know how much trust to put in it.
And that while we put our trust into a CA to validate and verify identity information, how much trust should be put into them? What lengths do they go to to ensure identity? All CAs are not created equally.
And there's some things that we should know, like what criteria do they use to not only issue a certificate, but also criteria about how they revoke certificates and renew certificates as well.
You know, if we receive the certificate from a CA that theoretically just signs off on any certificate request without doing any sort of validation, then we wouldn't want to put a whole lot trust into any certificate they sign.
On there other hand, if we received a certificate from a CA that, you know, went and visited the requestor, examined their articles of incorporation, and looked at the systems that were going to be used by the certificate, then we would probably place a whole lot of trust into any certificate that they signed.
Now, of course, neither of these scenarios are realistic for a commercial CA, but my point is that we may want to place different levels of trust into a certificate that we receive based on how the CA goes about validating the identity.
So now I'm sure you're asking, how do we know the criteria that a CA uses to validate identity? Well, a certificate authority, and in this case certificate authority means the company, the certificate authority publishes a certificate practice statement, which is a set of documents that define the criteria for issuing, publishing, archiving, revoking, and renewing certificates.
Okay so great, we've got a certificate and we know that the CA has policies.
So how do we find these policies? Well, we can go to the CA site and search around for the policies, although there might be different policies depending on how we want to use the certificate.
And there are probably a bunch of policies in the repository that may or, you know, may not apply.
And now fun, isn't it? Well, we don't have to do any of that.
The x.
509 v3 standard defines an extension named certificate policies.
And this extension holds the URL where the certificate practice statement repository lives so that we know where to find the documents that we want.
And being the curious person you are, I'm sure you would like to know how exactly the extension value is populated, and how the extension is written to the certificate.
Although I'm sure you probably already figured out that it's the policy CA.
This is the guy who writes the certificate policies extension into a certificate authority certificate, and as we just said the extension's value holds the URL where the cps repository is located.

Using Public and Private Keys When it comes to encryption, decryption, signing data, and verifying signatures, it can be confusing as to which key is supposed to be used for an operation if you're new to the concept.
The two things to remember here are who has the data and what do you want to do with it? So let's start with encryption and decryption.
We encrypt data so that we can control who is able to read the data.
So let's think about using a private key to encrypt data and a public key to decrypt it.
Well, in this scenario, anyone with a public key can decrypt the data, and since our public key is just that, public, anyone can read the data that we've encrypted.
So that really defeats the purpose of encrypting data.
If we encrypt data with the public key, then only the person with the private key can decrypt the data, which makes a lot more sense.
We're encrypting data that can only be decrypted by the person who holds the corresponding private key.
So we encrypt data with the public key and decrypt it with the private key.
Signing data and verifying signatures goes the other way around.
So we sign data so that anyone who has the data can check and make sure that the data really came from us.
If data is signed with the public key, then only the person who has the private key can verify the signature.
That really doesn't do us any good because if the data is signed with the public key, and, again, the public key is available to anyone out there, then who knows who signed the data.
And only the person who has the private key can validate the signature.
And this totally defeats the purpose of signing data because we don't know who signed it and only one person can validate a signature.
If we sign the data with a private key, then anyone who has our public key can verify that the data was signed by us, which is the purpose of signing data.
So we sign data with a private key, and verify the signature with the public key.

Getting a Certificate Signed by a CA Once we've generated our key pair, we need to get our public key by a certificate authority so that it will be trusted when we make it publicly available.
And this process starts with generating a certificate signing request.
Once that is done, we'll add our public key, information about who we are, and any extra information we want to have written to the signed certificate.
The information about who we are is written in a format called distinguished name.
And I cover that in detail in the certificate identities topic in the x.
509 certificates module.
But for right now, we read this identity as Donald Mallard in the security unit of Duck Airlines, which is located in Cleveland, Ohio in the United States.
Extra bits of information that we want to have added as part of our signed certificate are called extensions.
And I talk about these in more detail in the certificate extensions topic in the x.
509 certificates module.
The last thing we do here is to sign the certificate with our own private key, and then we send it off to a certificate authority to be signed.

Revoking a Certificate A fundamental tenant of trust in a PKI implementation is the ability to revoke a certificate.
And there are any number of reasons that a certificate authority might want to revoke a certificate.
Ranging from a malicious compromise of any part of the certificate authority to employee separation from a company to any other reason the certificate authority deems necessary.
The mechanics of revoking a certificate are pretty simple.
The CA that issued the certificate will add the serial number of the certificate that is being revoked to their certificate revocation list.
Now when we receive a certificate, it's our job to make sure that the certificate is valid and trustworthy.
So, along with checking that the current data is within the valid from and valid to dates on the certificate, we will need to check the certificate authority's certificate revocation list to ensure that the certificate we're validating has not been revoked.
Now, clearly, we need to know where the CRL is and how to get to it in order to do that check.
There will be a certificate extension named CRL Distribution Points, and that will have the URL to the certificate revocation list.
Although it's becoming less common to download an entire CRL and compare serial numbers to find the status of a certificate.
You'll usually find that the CA has an instance of the online certificate status protocol that you can use to check the status of a certificate.
And OCSP is a request response service hosted by the certificate authority that will return the status of a single certificate that you provide in the request.
We'll find the URL for the OCSP service in a certificate extension named Authority Information Access.
And this wraps up our introduction to the public key infrastructure.

The Public Private Key Pair Overview Welcome back to this course about PKI and asymmetric cryptography.
I'm still Ed Curren, and in this module, we're going to get into key pairs.
What key pairs are, why they exist, and how they differ from symmetric keys, the math behind the keys, where and how we store keys, and of course we're going to write some code and generate and store some keys.
So go ahead and settle in and we'll get going.

The Key Pair What's the difference between symmetric and asymmetric cryptography? Well, in symmetric cryptography, both sides use the same key to do the encryption and decryption of the data.
The symmetry is that the same key is used on both sides.
Which brings up a fundamental security problem with symmetric cryptography.
One side is going to choose the key and it can be the greatest most secure key in the history of cryptography, but how do you get that key to the other person without it being compromised? I mean, sure, if they're close by, you could write it down on a piece of paper, put the paper in a double zip, double lock briefcase, destroy the pad of paper that you used so that indentations of the password are gone, hand carry it to them, make them memorize it, and then eat the paper.
But if they aren't close by, then things could get complicated.
Plus, odds are that the other person won't be able to remember the key, so they'll write it down, which makes our security efforts worthless.
This also assumes that a person will be there to provide the key when it's needed.
If an application or automated process of some sort needs to use the key, then it has to be stored somewhere that the process can get it.
And that most likely means that it will be saved in an unencrypted configuration file that is accessible to any number of people.
The bottom line of all of this is that it's extremely difficult to implement ongoing reliable protection of a symmetric key.
And it's this problem, specifically exchanging data in a secure way over an untrusted network, that was a motivating factor in creating asymmetric cryptography.
With asymmetric cryptography, we have two keys.
One key is public and available to everyone, and the other key is private and only available to the owner.
So let's look at how all of this works.
If you've watched any of my other courses, you'll be familiar with Duck Airlines who are proud to have a 100% landing rate, so much that their tagline is Duck Airlines, we hit the ground every time.
There's a critical situation unfolding tonight onboard Duck Airlines flight 657.
They've run out of chicken and only have pasta left.
Given the sensitive nature of this potential chicken Armageddon, it is, of course, critical that flight 657 gets an emergency message to operations.
But this, of course, is only half of their battle because if rival airlines learn of this disaster, they will most certainly launch a devastating ad campaign to humiliate Duck Airlines and drive their passenger loyalty into the ground.
Fortunately, we have one of our best captains at the helm tonight, Captain Mallard, who at this very moment, I'm sure is entering the message into the onboard data link computer.
Now, as we know, Duck Airlines fleet of aircraft are each equipped with the state of the art squawk 2000 series of data link computers.
Which is truly fortunate because the squawk 2000 series automatically encrypts messages with the public key selected by the flight crew.
No doubt Captain Mallard will use the flight operations public key to ensure that only they will be able to read the message sent by flight 657.
As we also know in situations like this, flight operations will need proof that this message is genuine and not some clever roost to destabilize Duck Airlines at its core and bring the airline to ruins.
As it turns out though, the squawk 2000 automatically signs the message with the aircraft's private key, so there should be no problem with validating the message.
So what we've just done here is that we've sent the message over an untrusted network, securely and reliably.
But as with anything, there are drawbacks to using key pairs.
It's slower than using symmetric cryptography because the data being encrypted has to be broken down into small chunks.
For example, if we're using a 2048 bit RSA key, the max amount of data that we can encrypt is 245 bytes.
And then that 245 bytes is padded, so the chunk of data that is sent is actually 256 bytes long.
And that 11 byte difference can add up.
For example, if we're sending 1 MB of data using a 2048 bit RSA key, there will be nearly 45 K of overhead added.
Also, there isn't any specific standard of how the data is split into chunks and then reassembled, which can increase the time required to send data using PKI, or more specifically, in this case, RSA.
So in practice, we'll usually generate a symmetric key and then encrypt that key with the other party's public key, and then the two parties will use the symmetric key to do the encryption and do the decryption of the data after that.

The Math of Key Pairs The key to the security of asymmetric cryptography lies in the discrete logarithm problem.
Which means that it's easy to generate our key pair from the prime numbers that we start with, but it's extremely hard to get those prime numbers from the key pair.
And the way we do this is by using modular arithmetic.
Along with those two very large prime numbers, we also need the modulus of the two prime numbers, Euler's totient function of the modulus, and the encryption and decryption exponents.
So the first step in calculating our key pairs is to choose a couple of really, really big prime numbers, numbers that are hundreds of digits in length.
And we label these two numbers p and q.
Doing the math in this example with really large numbers would be confusing, so I'm going to run through this using a couple of small prime numbers.
And just a disclaimer here before we get going, remember that the security of the algorithm lies in the fact that it's so difficult to reverse calculate the original numbers that it's impractical to do so.
Using the tiny numbers that I'm going to use in this example are really easy to reverse calculate.
So don't use them in the real world.
Okay, so for this example, I'm going to set p to 3 and q to 11.
The next step is to calculate the modulus for the key pair and the modulus has to be common to both p and q.
So we simply multiply p and q together and then we're going to label the product of this multiplication as n.
Next, we're going to apply Euler's totient function, also known as the phi function, to n.
If you'd like to get deeper into how this works, there are a number of good resources online.
For our purposes, all we need to know is that phi of a prime number is that prime number minus 1.
Well, almost all we need to know.
Our value of n is 33, which isn't a prime number, but the phi function is also multiplicative, which means that phi of p times q is equal to phi of n.
So in our case, phi of n is phi of 33, which equals phi of p minus 1 times phi of q minus 1, which is also 2 times 10, which is 20.
We have two variables left, which are arguably the stars of the show, they are the public and private key exponents.
Our public key has to be a prime number less than phi of n, and also has to be coprime to n.
Meaning that the greatest common devisor between our public key exponent and n is 1.
Picking a random number that is less than phi of n isn't difficult, but finding one that is coprime to n can be more difficult.
So in practice, it's often the case that, in RSA anyway, the public key will be 65537, and 65537 is often used because it's one of _____Faraday's prime numbers, and this is another area where I invite you to explore it on your own if you're interested.
For our example here, I'm going to use one of _____Faraday's other prime numbers, which is 17.
And we label the public key exponent as e.
Which brings us to our last, and in no way least, variable, the private key exponent.
Something I want to point out here is that the private key is the inverse of the public key.
So a cool property about the keys is that either one can be used for encryption or decryption and for signature or verification.
And this is reflected in how we calculate our private key exponent, because we are essentially looking for the inverse of e.
Although, it's mathematically more complex than the inverse of e, because we're actually looking for something called the modular multiplicative inverse of e, which is also expressed as e times d mod phi equals 1.
So the way we solve this is by using the extended Euclidian algorithm.
Now calculating the modular multiplicative inverse of e using the extended Euclidian algorithm is just about as complicated as saying modular multiplicative inverse using the extended Euclidian algorithm.
And I think going into the details of how it's calculated has too much potential to be confusing.
It's also not critical to the overall understanding of composing the key pair.
But if you are curious, please do go and explore it further.
All that being said, when we pass e and phi of n into the extended Euclidian algorithm, we wind up with a value of 13, which we assign to d.
Now the keys are comprised of their exponent value, which is either e or d respectively, as well as n.
So our public key is a composite of e and n and our private key is a composite of d and n.
And this will make more sense as we go through the example here.
So let's take these keys for a test drive here.
For the sake of clarity and simplicity, we're going to encrypt and decrypt the capital letter H, which has an ASCII decimal value of 72, and we're going to label this as m.
We calculate the encrypted value using m to the power of e mod n, which is 72 to the power of 17 mod 33, which winds up being 30.
So 30 is our encrypted value and let's label this guy c.
To decrypt c back to our original value m, we use the same formula, replacing m with c and e with d.
So here we have 30 to the power of 13 mod 33, which gives us 6.
Wait, what? Well another important factor here is that the value that we're going to encrypt has to be less than our modulus, otherwise the decryption will result in the value that isn't the one we started with.
So let's encrypt a carriage return, which is 13, and 13 is less than our modulus 33.
And when we run it through our formula, we get an encrypted value of 7.
But more importantly, it decrypts back to our original value of 13.
All of this is great, but in real life we can't decide to encrypt something else because the message that we want to encrypt doesn't work with our keys.
That means that we need bigger keys.
So we need two prime numbers that when multiplied together will be greater than 72.
So I'll use 17 and 19, which gives us a modulus of 323 and a phi of 288.
So let's set e to 11, which gives us a d of 131.
Now when we encrypt 72, we get an encrypted value of 98, and more importantly it decrypts back to 72.
Now given the size of the numbers that are used in real systems, I think we'd be pretty hard pressed to find a situation where this would happen.

Storing Keys The key pairs we generate usually aren't transient, unless we're using them for timestamping.
In this course, we're assigning key pairs to lasting entities like people, servers, or organizations.
So we need to keep them some place where we can not only access them, but it's also secure.
And this is where key stores come into play.
The file format for our key stores on computers is defined by PKCS#12.
And I say on computers because the standards that cover cryptography hardware, like tokens or dongles, are defined in PKCS#11 and 15.
And I'm not going to get into cryptography hardware in this course, but you should have enough knowledge after finishing this course to be able to explore that on your own.
The PKCS#12 file format is fairly complex, so I'm not going to go into too much detail about it, but let's take a look at a high level how data is stored.
It defines a data structure called a safe bag, which holds individual data items.
Although, when we add data, we use one of six bag types that derive from a safe bag.
The key bag and PKCS8 shrouded key bag types are used to store a private key.
The cert bag type is used to store a certificate.
The CRL bag is used to a store a certificate revocation list.
There is a secret bag type, which is used to hold user defined data.
And the last bag type is the safe contents type, which is a bit of a misnomer in a way because it's the top-level data structure that holds all of the bags in the P12 file.
Now with the exception of the safe contents type, each bag holds a single data item, but several of the bag types can hold different types of the objects that they contain.
So, for example, there are a number of different certificates that are used within the public key infrastructure that serve different purposes.
But regardless of the certificate type, it's stored in a cert bag.
The P12 format also makes extensive use of object identifiers, and if you're hopping into this course here and need to get up to speed on object identifiers, I get into detail about them in the introducing the public key infrastructure module.
So with that, let's generate some keys to store.

Summary We've taken a deep dive into the concepts of key pairs, and while this has been informative, possibly even interesting, if you're a hardcore computer geek like I am, it doesn't really help us in a practical way when we sit down and actually need to generate keys.
Fear not though, we will be generating plenty of keys in our project later on.

X.
509 Certificates Overview Hello and welcome back to this course on asymmetric cryptography.
I am indeed still Ed Curren, and in this module we're going to get into the details of public key certificates.
After a quick primer, I'll cover the different types of certificates and the various pieces of information that they contain.
We'll figure out how to know when we can trust the certificate and when we cannot.
In a bit, when I get into certificate identity information, I'll offer up some context around how x.
509 certificates came from the x.
500 directory service standard, which is the foundation of directory services like LDAP or Active Directory.
I'll take you through certificate extensions, what they are, how we use them to configure certificates, and how we can store extra information in there.
And it goes without saying that we'll get back into our project and write some certificate code.
But apparently I'm saying it anyway.

Certificate Types We're going to talk about three different types of certificates in PKI.
Each of them has their own purpose and hold different information.
Actually, that's not quite true.
There are a few fields that are common to all three, and the first time that we encounter a common field I'll cover it, but when we run into it again, I'll point it out that it's part of the certificate structure, but I'm not going to go into detail about it all over again.
The three certificate types that we're going to look at are the certificate request, the certificate, which is the type that we think of when we're talking about certificates, and the certificate revocation list.
There's another type of certificate that's similar to these three, which is the attribute certificate.
It's a bit of an outlier though because the certificate types that we're looking at deal with authentication.
The attribute certificate deals with authorization, or to put it another way, we're looking at who they are.
Attribute certificates look at what they're allowed to do.
That difference alone isn't a big deal, but to get into attribute certificates, I'd have to get into the privilege management infrastructure.
It's very similar to PKI, but it would still take quite a while to cover the relevant differences and really it's not in the scope of what we're talking about in this course.
One last note before we get into the certificate structures.
There's a lot of discussion about certificates in the context of SSL certificates.
This sometimes leads to confusion that these are their own certificate types.
SSL certificates are just a plain old certificate with certain extensions added to it, and we're going to cover certificate extensions in a bit.
And with that, we're going to take a look at the certificate structure.

The Certificate Structure We're going to start with the fundamental certificate structure.
It's not called a fundamental certificate, I just mean that it's not one of the specialized types of certificates that we're going to be talking about later.
This type of certificate is essentially a way to attach attributes and information about the public key to the public key.
And we trust the information in the certificate when it's been signed by a third party that we trust to verify that the information is correct.
So there are six fields that make up the certificate.
The version field is simply the version of the certificate structure.
At the time of this recording, the current version is version 3, but it really looks like version 3 will be the latest version for quite a while.
The serial number field is like any other serial number in that it has to be unique.
But there's a catch here, it has to be unique within a certification authority, so it's possible that you could have two certificates with the same serial number, but issued by different certification authorities.
It's not likely, but it's possible.
The signature algorithm is the algorithm that was used by the certification authority to sign the certificate.
And there are several algorithms that are allowed, but SHA is the preferred one.
And you almost always find RSA encryption used in conjunction with the SHA digest.
You don't have to use RSA encryption though, I've come across some certificates that use elliptical curve encryption or some other PKI algorithm, but RSA is the most common.
And if you look at the signature algorithm, you'll most likely see something like sha256WithRSAEncryption or it may be shortened to something like sha256RSA.
The issuer name is the distinguished name of the certificate signer, and that signer will usually be a certification authority.
Now a distinguished name isn't the simple name like John Smith or Pluralsight.
It's made up of a few pieces of information.
And we're going to take a look at distinguished names later in this module, but distinguished names are usually made up of a country, organization, and the common name.
Along with the issuer name, we have another distinguished name field for the key owner called subject name.
The validity period sets the start date, along with the end date.
You can set the start date to sometime in the future, but the certificate usually becomes active when it's created.
And the certificate can also expire before the end date on the certificate if the signer's certificate expires first.
Since we use a certificate as a way of giving information about who owns the keys and what they're allowed to do with the keys, we, of course, include the public key as part of the certificate.
The last field in the certificate is the collection of extensions.
And extensions are primarily used to restrict what privileges the certificate has, or more accurately what privileges the key has.
For example, if the key is used for encryption or used for signing, whether or not the certificate is owned by a certification authority and/or how to get certificate revocation lists.
However, there aren't any restrictions on what information can and cannot be put into the extensions collection.
So, we're free to do things like put our own information in the extension field.

The Certificate Signature Request Structure We hear the word trust a lot in PKI because we're taking information about the owner of a public key at face value.
We trust that the information is real and correct.
And this is really a foundational element.
Without trust the public key infrastructure just doesn't work.
In order for us to trust the information in the certificate, it has to be validated by a third party.
This third party is the certification authority.
They take on the responsibility of ensuring that the information attached to the public key is real and correct.
We submit our information to the CA for validation in the form of a certificate signature request.
This structure has four fields, the version, the subject name, the public key, and the collection of extensions.
And this should look familiar because it's a subset of the fields contained in the signed certificate structure that we just looked at.
So, if we compare the fields in the signed certificate to the fields in the certificate request, we see the fields that the CA adds to the signed certificate.
It issues the serial number, provides the signature algorithm that it used to sign the certificate, provides the information about itself, and sets the validity period.
The subject, public key, and extensions information is simply copied from the certificate request into the signed certificate.

The Certificate Revocation List Structure What do we do when the key is compromised? How do we tell people to no longer trust the certificate? Well, when the key is compromised or it becomes untrustworthy, the certification authority that issued the certificate will revoke it by including it in a certificate revocation list.
Which, as the name suggestions, is a list of certificates that are no longer trustworthy and haven't yet expired.
Certificate revocation lists are also typically issued at regular time intervals by the certification authority, although there's no mandate on how often certificate revocation lists are issued.
Some certification authorities issue a certificate revocation list at least once daily, but there are also certification authorities that issue certificate revocation lists as infrequently as every 90 days.
So, looking at the CRL data items, we've seen three of these already in the certificate structure.
But going back to the time interval I was just discussing, the this update and next update fields indicate when the CRL was issued and when the next CRL will be issued.
Of course, given that the purpose of the CRL is to provide notification of revoked certificates, it's a good idea to include the list of certificates that have been revoked.
The last field here in the CRL is another one that we learned about earlier, which is the extensions field.
And this field is the only optional field in the CRL structure.

Certificate Chains When we get a certificate, how do we know if we can trust it? Well, when the certificate is exported to a file, more than just the end certificate is written out to that file.
Each certificate involved in signing the end certificate are also written out.
And this is called a certificate chain.
Using a certificate chain lets the receiver authenticate it as trustworthy because it has all of the certificates involved in signing.
Back in the introducing the public key infrastructure, I talked about certificate authority hierarchies where there is a root certificate authority, which can have multiple levels of intermediate certificate authorities.
The lowest level of which will ultimately sign the end certificate.
So to validate the end certificate, we'll check each signature as we walk back up the chain.
Starting with the end cert, the first thing we do is to calculate the hash value of the certificate using the algorithm specified by the signing certificate, which in this case is the intermediate certificate authority certificate.
Next we decrypt the signature in our end certificate using the intermediate certificate authority's public key, and then we compare the two signatures.
Assuming that the signature is valid, we'll repeat these steps for each of the certificates in the chain.
And we have one more step when we get to the root certification authority, which is to ensure that the root CA is part of our collection of trusted roots.
Assuming that we trust the root CA, then we trust the end certificate.

Certificate Identities So personally I like to understand as much as I can about the origins of the technology that I deal with.
Mostly because it just fascinates me, but also sometimes it can give me useful insight and context that can help me solve problems.
I have no idea if the info I'm about to share with you will help you solve a problem, but it will provide insight.
So back in the dark ages of the late 1980s, 1988 to be precise, the International Telecommunications Union wrote this x.
500 series of standards, and these set of standards defined a directory service.
So, if you remember Novell NetWare, then you're old like me, but we can also look at Active Directory as an example of a directory service.
And in a directory service, we keep several bits of information about a person or a server or some other entity, so for a person it would be name, address, phone number, email address, or any number of other attributes that we find useful.
X.
500 combines any number of these fields together to form a distinguished name.
Now x.
509 was defined as part of the x.
500 series and was really designed to be the security element for interacting with a directory service.
The x.
500 standard also uses public private key pair cryptography, at least in part, because it provides a secure way to ensure identity.
We can check a signature against a person's public key to, you know, make sure it's really them.
So we store the public key as part of a record in the directory.
Connecting all of the dots here, the issuer's identity and/or the subject's identity are written to a certificate in the form of their distinguished name.
So, again, there are many fields that a distinguished name can use, but there are only six that are usually used in a certificate, which are the country, the state or province, the locality, the organization, the organizational unit, and the common name.
So a couple of notes to wrap up this look at certificate identity.
Only the country name and common name are required for a certificate identity field, and also the country name has to be written as the two-letter international country code, and if you ever need to look it up, you can find it in the ISO 3166 standard.

Certificate Extensions Before version 3 of the x.
509 standard, a certificate only held information about the subject, the issuer, validity period, signature specifics, and the public key.
Version 3 of the x.
509 standard added extension fields, which allows us to add additional information as part of the certificate.
An extension field is essentially a key value pair where the key is an object identifier.
So what's an object identifier, you ask? Well, an object identifier, also known as an OID, is a string of numbers that identify a unique object in a repository.
Now OIDs are controlled by the international standards organization, and using an OID registered to someone else, or not registering an OID that you're using, might have legal consequences depending on the situation.
So I'm going to tell you how to register your own OID here in a minute.
But first, we're going to hop over here to an online OID repository browser that does a fairly nice job of navigating the repository and presenting the information.
There's a specific OID that holds certificate extensions and it's 2.
5 .
29, which translates into the joint ISO and ITU repository.
Then down to the directory services node and arriving at the certificate extensions node.
And if we look, there are 70 certificate extensions registered here.
Well, some of them are obsolete, so not quite 70.
We can also include information that we define in an extension field.
This isn't common, but if there's a good reason for you to do it, it can be done.
The first thing to do is to have an OID assigned to you, which you can do via the IANA.
They'll create a node for you under the private enterprise OID and you can then create any structure of OIDs under the one assigned to you by the IANA.
An extension is also marked as either critical or noncritical.
If an extension is marked as critical, then the application validating the certificate must be able to interpret the extension.
If it can't, then it must reject the certificate.
So that's about it for this module.
In the next module, we're going to actually write some code, which is everybody's favorite.
So stick around and we'll implement all of the stuff I've been talking about.

Writing the Code Overview Hello and welcome back.
I'm still Ed Curren, and this is probably the most interesting module because we're going to write a certificate authority and we're also going to write an application that uses the CA, as well as doing that whole asymmetric cryptography stuff.
More specifically, we're going to set up the trust us certificate authority, create key pairs in a couple of different ways, which will make sense later on.
We're going to create certificates and we're going to use all of the above to encrypt and decrypt data, as well as sign and validate those signatures.
So let's go.

Fight 657 We're going to pick up on our unfolding drama on board flight 657.
You may recall from the public private key pair module, we have a chicken Armageddon looming and must get a message to flight operations without rival airlines learning of this truly massive faux pas.
This means that we need to send an encrypted and signed message.
To do that, we need a public private key pair, which means that we need a public key infrastructure.
So we're going to implement a public key infrastructure.
Before we start writing the code though, I'm going to cover a couple of notes about the project, introduce you to the trust us certificate authority, and cover the data structures that we're going to use to move data around the projects.

The Trust Us Certificate Authority Welcome to the Trust Us Certificate Authority.
We're clearly a highly reputable organization because what dishonest person would name an organization Trust Us.
We proudly serve all areas of the world and while we're headquartered here in Cleveland, Ohio in the United States, we have prestigious branches in Mumbai, Berlin, Santiago, Moscow, Sydney, and Cape Town.
Our root CA is kept in our Cleveland headquarters on a machine that is powered off, not connected to any network, and physically sealed in a super secure vault guarded by trained attack hamsters.
Well, you can never be too careful.
Before we took the root CA offline, we had it sign the certificate for our policy CA.
The policy CA, of course, being the CA that attaches the certificate authority's certificate practice statement to a certificate.
If you're not familiar with certificate practice statements, you can find our discussion on that in the introducing the public key infrastructure module.
Once we have our policy CA, we then task it with signing certificates for our intermediate CAs, which are located in our branch offices around the world.
Each location covers a specific geographic region.
Cleveland serves North America and the northern part of Central America.
Mumbai serves India, the Middle East, and lower Asia.
Berlin serves Europe.
Santiago serves southern Central America and South America.
Moscow serves Northern and Eastern Asia.
Sydney serves Australia, as well as southern Asia.
And Cape Town serves Africa.

The Project The project is made up of two parts.
The first part is the certificate authority, which is found in the Pluralsight Trust Us Certificate Authority solution.
I decided to use the cryptlib library for building the certificate authorities in this course for a couple of reasons.
One being that we must explicitly define the configuration of the various objects that we're working with, like keys and certificates.
So as we write the code, you'll be able to see more clearly how the concepts that we covered in the material are implemented in the code.
Also, it has a simple API that really lets us focus on getting our CA up and running without the need to research a large set of classes and methods just to find the functionality that we need.
You'll see all this in action when we start writing the code here shortly.
One extra bit of setup we need to do for cryptlib is to set up an ODBC driver.
You can choose the database and the ODBC setup you prefer.
The only caveat is that the data source must be named TrustUs, only because that's the name we're using in the sample project.
I'll be using SQLite as the database, but it really doesn't matter which database you want to use.
Also, the cryptlib dll must be located in the same directory as the executable.
So in the project properties, Build Events, you'll see this copy command in the post-build event command line box.
The other part of the project is the Duck Airlines application, which is found in the Pluralsight Duck Airlines cryptography solution.
This application uses Bouncy Castle as the cryptographic library.
Now we don't need to use an external crypto library for this application, but it makes it much easier to write and understand the code, which is the goal here.
You're going to find that the project has a lot of code in there already.
I primarily did this so that you have some sample code to play with as you keep exploring asymmetric cryptography.
You'll also find that there are a few methods that don't have any code written.
These are the methods that we're going to write together in this module.

Data Transfer Objects Before you see these classes in the code, I'm going to walk you through four data structure classes, or data transfer objects, if you prefer, so that you have some context, not only about the data that they hold, but also the areas within our PKI implementation where they will be used.
And while I've been talking here, you've been looking at key configuration.
This guy is involved in every service our code provides to the user because he holds the properties that are used in generating and storing key pairs.
On the storage side, we have file names for storing the private key, the certificate signing request, and the signed certificate.
On the non-storage side, we have the key label, which is effectively a tag that cryptlib uses to find the private key that we're looking for within a file.
We also have the private key password that's used to encrypt the private key within the file.
And lastly, we have the distinguished name.
And if you aren't familiar with distinguished names, you'll want to watch the part of the x.
509 certificates module where I cover distinguished names.
There are a number of fields defined for distinguished names, but we're only going to use six of the most common ones for the distinguished names field in our certificates.
Country, stage, locality, organization, organizational unit, and common name.
Certificate configuration derives from key configuration.
And this guy holds the properties that identify the CA key that's going to sign the certificate request contained in the key configuration.
Now before this gets confusing, let me say that these data transfer objects don't mimic real life.
These are structured to pass data that we need around within our project code.
In real life, the certificate signing request will be passed from a client to the CA.
And we wouldn't be telling the CA which key to use to sign our certificate signing request.
There are three properties in here, which are the file name of the private key that will be used to sign the CSR, the keys label, which is the tag that cryptlib uses to find the key within the file, and the password to decrypt the private key.
Finally, we have the certificate authority configuration, which derives from certificate configuration.
And this guy holds the properties that are used in setting up the certificate authority, specifically the path in the file system where we will read and write the keys, the ODBC datastore name for the CA certificate store database, the URL that clients can interact with to access the certificate store database, the URL where clients can get the certificate revocation list, and finally, the OCSP URL.
And that's it, let's look at some code.

The Data Now that we understand the structure of the data classes, let's look at the data they hold for the project.
Under the Data folder, you'll find ConfigurationData.
And this class holds the configuration settings for all of our CAs.
They all have the basic information about where to store the generated keys, the distinguished name, the key label, and the private key password.
Beyond the basic data, there are subtle differences between the root and policy entries as compared to the other entries and most of them involve the signing key.
If we look at any of the intermediate CA entries, the signing key property identifies the policy CA key as the key to be used to sign the certificate.
The policy entry identifies the root CA as the signing authority, and the root CA doesn't have any signing key information because it's self-signed.
The root CA also has a couple of other entries.
These two certificate store properties are for a certificate store database.
After our CA issues a certificate based on a certificate signing request, our CA will store a copy of it in the cryptlib certificate stored database.
These last two properties here specify where we can check the validity of a certificate using OCSP and where we can find and download a current revocation list.

Initializing the CA We're going to start by setting up the certificate authorities, which is a far more complex task as compared to the customer side of generating keys and getting a certificate to do encryption, decryption, and signing and verification operations.
And doing it this way, so that we'll have a CA up and running when we have a generated certificate signing request from the Duck Airlines application.
We'll be able to submit it to the CA and then have a signed certificate returned to us right away.
Now if you would prefer to go through the Duck Airlines application code and then come back to this, you can absolutely do it that way.
So open up the TrustUs certificate authority project if you haven't already done so and go to Program.
cs.
Now the syntax of most of the code we're going to be writing in this part of the project may appear a bit odd since it won't be following C# coding style norms.
That's because cryptlib is written in C and provides language wrappers to interoperate with the library from other languages.
So you'll see more of a C style of code in many places.
For C# it's cryptlib.
cs that providers interop services with cryptlib.
The first sign of C that we're going to find is the initialization and termination of cryptlib.
C# code that we compile runs within the common language runtime as managed code, and so allocation and freeing of resources, like memory, for example, is handled by the CLR for our C# code.
C, on the other hand, is a lower level language that compiles directly into machine code.
So the C code has to handle the resource allocation and deallocation on its own.
To initialize cryptlib, we call the crypt.
Init function, and I'm doing that right here in the Main method of our code.
If we call any other cryptlib function before we call init, we're going to get an error.
On the flip side of that, when we're done, we call crypt.
End.
What happens if we don't call End? Well, we orphan allocated memory, which would lead to a memory leak, but more importantly that information is now accessible by other applications running on the machine.
So the last line of Main will be crypt.
End.

Creating a Cryptlib Key Pair Pretty much everything we do in the CA involves a key pair.
So the first thing we're going to do is generate a key pair.
In the project, you should see the Key class, and when you open that up, we see that there is a GenerateKeyPair method just waiting for us to write some code.
We get an instance of the KeyConfiguration class that we looked at earlier, and we return an integer.
I'm sure that the KeyConfiguration class makes sense, but what is the integer that we're returning? Well, hold tight on that, it'll make sense here in a minute.
So the first step here is to set up a cryptlib context, and we can think of it as a kind of container that we configure for doing a cryptographic action.
Containers are configured through attributes, like algorithm to use, key size, initialization vector, salt values, any sort of information that's required for doing a cryptographic action.
Generating a key pair is definitely a cryptographic operation, so we'll name our context keyContext, which is created by calling CreateContext.
The first parameter for CreateContext is a user.
Now cryptlib has access control as part of the library, but in our case, we aren't worried about access control, so set is as UNUSED.
The other parameter that we need to provide is the algorithm to use, and since we're generating a key pair, we want to use a PKI style algorithm.
Cryptlib provides an RSA algorithm for this stuff, so we set this parameter to ALGO_RSA.
The label for the key pair is attached to the context by setting it as a context attribute, and cryptlib has two types of attributes, which are an integer attribute and a string attribute.
The label is a string, so we call the SetAttributeString function.
The first parameter is the context to which we want to apply the attribute.
Next is the type of attribute that we're setting, which in this case is the context info label, although it's a bit abbreviated here.
And lastly, we set the label value.
We also need to set the key size for the key pair, which is an integer value, so we'll call SetAttribute and pass it the same set of parameters.
Our context, the attribute type which is CTXINFO_KEYSIZE, and the key size itself, which will be a 2048 bit key.
Now cryptlib uses bytes rather than bits for the key size.
So we'll just divide it by 8.
I could have just put 128 in there, but we tend to use bits to describe the size of a key, so I wrote it this way to make it more easily understood.
That's all we need to do to configure it.
So now we generate our keys by calling cryptlib's GenerateKey function and pass our context into it.
And once the keys are generated, they will be contained within the context.
So great, we have our keys, which will be obliterated when we destroy the context.
So we need to write them out to a key store.
This is where the methods return type of integer comes into play.
We're about to write the private key to a key store file because aside from encrypting it, we store it as is.
The public key, on the other hand, is usually attached to a certificate signing request that we would create as part of the key generation process.
Certificate authority certificates are different.
Technically a CSR cannot have the basic constraints extension set to CA.
A CA cert is directly signed by a CA certificate of higher authority.
The root CA though is the highest authority, so he self-signs his certificate.
We're also dealing with three different CA types here, each of which we'll need to generate a key pair.
So I pulled the common certificate generation code into its own method.
In order to get the public key back to the certificate, we pass back the keyContext handle rather than destroying the context here.
To write our private key out to a file, we open up a key store with the KeySetOpen function.
The first parameter is for our user and, again, we aren't worried about access control, so we'll give it a value of unused.
And next we tell it the type of key store to open.
There are a few different types of key stores, but the only type that we can use to store our private key in cryptlib is a file.
So we'll set this as a KEYSET_FILE.
And in this case, KeySet and KeyStore are different names for the same thing.
Next, we pass in the file name to use, and a quick side note here, the directory that we want to use has to exist before we create a keyStore.
If the directory doesn't exist, then we'll get an error.
The last parameter has to do with read/write access to the keyStore.
The values we can set for this are create, none, or read only.
Create will create a new keyStore file if the file doesn't exist already, or delete the existing file and create a new one if a file with that name already exists.
None will open an existing keyStore file for both read and write operations, but it throws an error if the file does not exist.
And finally, read only is just that, read access to the file store if it exists.
So we have a bit of a conundrum here.
If we try to open a keyStore, but it doesn't exist, then we'll get an error.
If we use create and there is a keyStore already, then we'll blow away all of our keys.
Personally, I don't like erasing all of my existing keys each time I want to add a new key to a keyStore.
So I'll try open the keyStore with the none option.
If the file doesn't exist, then cryptlib will return a negative 43, which is a not found error.
And this is C showing itself again, where it's common to return an integer as a result of what happened in the function.
If an error is returned, then the C# wrapper takes the result and translates that into an exception for us.
So wrap the KeysetOpen function in a try catch block.
If the file doesn't exist, then I'll create the file here.
The parameters are the same, except we use create instead of none.
We add the private key by calling the AddPrivateKey function, and we pass it the keyStore, our keyContext, and the password we're going to use to encrypt the private key.
And that's really it.
But before we exit, we need to do some clean up by closing the keyStore, which we do by calling the KeysetClose and passing in the keyset.
Normally we would also destroy the keyContext, but again, we need to use it for the certificate, so it's returned to the caller.

Creating Certfificates So we have the key pair and we've written our private key out to a key store.
Now we need to take care of the public key.
Now strictly speaking, we don't need to attach out public key to a certificate in order to use it.
After all, when the certificate is passed to a method that will be using encryption or signature validation, it's only interested in the public key.
The reason we pass public keys around using certificates goes back to trust.
If we get just the public key from someone, we can't know with absolute certainty if it's legitimate or not, although the same could be said about certificates.
But with certificates, we have a higher degree of confidence, and as such place a higher level of trust in it.
Okay so let's turn our attention to the Certificate class and the CreateCaCertificate method.
We have mostly the same setup as the GenerateKeyPair method in the Key class.
We're getting a key configuration and returning the handle for the certificate that we are creating.
We have one more parameter coming in though and it's the keyContext that holds the public key.
So the first thing we need to do is to create a cryptlib certificate object, and the way we do this is to call the CreateCert function.
The first parameter, again, is a user and because we aren't using the access control feature in cryptlib, we're going to set it to unused.
The other piece of data that CreateCert needs is the type of certificate that we want to create.
And this can either be a certificate or a certificate chain.
If you're not familiar with certificate chains, I've got you covered.
In the x.
509 certificates module, I spend a couple of minutes covering certificate chains.
Hopefully it's self evident that the root CA will be a certificate and the others will be certificate chains.
The root CA is self-signed, so it has no signature dependencies.
The others will have certificates signed by a CA of higher authority, so their type of certificate is a certificate chain.
The rest of our code here will be setting attributes on the certificate.
We'll start with attaching the public key.
The next several attributes will be setting the DistinguishedName properties.
And we're going to mark it as a CA certificate because all of the certificates we're creating here are CA certificates.
And last, we're going to pass the certificate handle back to the caller, like we did when we generated the key pair a short while ago.
We still need to assign the certificate and there are a couple of extensions that need to be added, but the extensions are different depending on which type of CA certificate we're creating.
So, first we'll finish up with the root CA certificate.

Creating the Root CA Certificate We're getting close to having our CA set up here, so it's time for us to open up the CertificateAuthoritySetup class and make use of the key and certificate code that we've written so far.
The first method we're going to write is the GenerateRootCaCertificate method.
And in here we have the full blown CertificateAuthorityConfiguration class being passed into us.
Before we can configure our certificate to be our root CA certificate, we need a certificate.
So we're going to create the key pair using the GenerateKeyPair method we just wrote, and now that we have the key pair, we can create the CA certificate.
There are a couple of root CA specific attributes for us to add.
The first one is that it's self-signed, which we do by adding the CERTINFO_SELFSIGNED attribute.
These next two aren't required to make this a root CA certificate, but we're going to provide the OCSP and revocation list URLs so that anyone who receives the certificate signed by us can check its validity.
We might have added these attributes to one of our intermediate CAs rather than the root CA, particularly if there's a high volume of requests that it would be overwhelming for one location to handle them all.
But in this scenario, let's say that we have a low volume of requests.
Now we are ready to sign the certificate, so we call SignCert, and we'll pass it the certificate to be signed and the context that holds the private key that we'll be using to find the certificate.
Now we have our public key certificate and, if you remember, a long time ago when we generated the key pair, after we wrote the private key out to the keyStore, we couldn't store the public key as is, and that it needs to be attached to a certificate of some sort in order to store it.
Well, here we are.
We can now write our public key out to the keyStore.
So open up the keyStore and we'll use the KEYOPT_NONE so that we can write to the existing keyStore and then call the AddPublicKey function, give it the keyStore and the public key certificate.
So now it's added to the key file, along with our private key.
We're not done yet though.
We can't use our key file as the certificate.
So we need to export the certificate out to its own file.
I've written a method in the Certificate class that handles the export of the certificate from cryptlib.
If you're interested, please, by all means, look at the method.
It's pretty simple, but for our purposes here we'll just call that method and pass the certificate in file name.
The last thing that we need to do here is to clean up the objects that we've created, including the keyContext and certificate that we created in the GenerateKeyPair and the CreateCertificate methods.
And that's it, we have successfully created our root CA certificate.

The Policy and Intermediate CAs We're signing the certificate with the key of a CA that has higher authority in the overall hierarchy.
So we need to load the key.
If you remember our discussion of the data transfer object classes, then you'll remember that this is the purpose of the CertificateConfiguration class.
So open up the KEYSET_FILE using the SigningKeyFileName held in the configuration.
And we're only going to read the key from this file, we won't be doing any writing to the file.
So we'll use the READONLY KEYOPT flag.
We'll call the GetPrivateKey function from cryptlib to, believe it or not, get the private key.
It needs the keyStore we just opened.
We're going to give it the name of the key to find, which is stored in the configuration's SigningKeyLabel property.
And, of course, we need to give it the private key password so that it can decrypt the key for us.
The rest of the code we're going to write here is nearly identical to the root CA certificate, nearly.
Generating a key pair is the same and creating a CA certificate is the same with the exception of the certificate type.
This time it's a cert chain rather than a certificate, because there's at least one more signer involved in the certificate.
We're also going to be setting certificate policy information on every certificate that we generate from this point on.
And we're doing this in order to stay conformant with RFC 5280, which basically says that if you want a valid CPS attached to your certificate, you have to have the extension in every CA certificate, except for the root.
There are a couple of possible object IDs for a policy extension.
The first one is a generic certificate policy object ID.
It's kind of like a wildcard policy in that any policy will match it during certificate chain validation.
The other policy extension object ID is in a completely different name space.
We would use this object ID if we wanted to attach a specific policy or multiple specific policies to certificates issued by our CA.
In this object ID, we have this node for a private enterprise number.
Now in development and internal testing, it's not too important to have a private enterprise number because you won't be interacting with the outside world.
But when you go to production, it's critical to have a private enterprise number that's assigned to you, or more likely your company.
And it's critical because there are potential civil or even criminal penalties for using somebody else's number or using a number that isn't registered.
It's easy to have a private enterprise number assigned to us though.
All you need to do is fill out this IANA form.
So let's say we've filled out our form and have been assigned number 99999.
This now becomes the object ID that we can use to enumerate our policies and attach specific policies to specific CAs.
Since we've broken out our CAs by geography, let's say that we have policies for each region.
We'll use 1 for North America, 2 for Asia, 3 for Europe, 4 for South America, and so on.
Now in our project code, we're going to keep in simple and we're not going to break it down any further.
So we set the certificate policy ID to our object ID.
We need to tell the folks where they can go to get the policy info, which we do by setting the CERTPOLICY_CPSURI attribute.
And from here on out, we repeat the same steps as before, which is to sign the certificate, add it to the keyStore, which holds the private key, export the certificate to a file that can be used by others, and clean up the cryptlib object.
So now that we have our CA certificates generated, we're going to get into the machinery of the certificate authority.

The CA Database For this project, we're going to limit our CA to issuing certificates from certificate requests.
Now I hope to be evolving the CA with more functionality that you can use to learn as time goes on.
And when I do make updates, I'll send that information out over Twitter.
So far, we've been using files to store all of the keys and certificates.
But this isn't really a good solution for the CA engine.
If we think about the lifecycle of a certificate policy, it's typically at least a year long, just because that's a typical validity period that a CA will issue.
And there are a number of events that can happen from the time that the CA gets the certificate request.
The first one is that the CA will validate the identity of the requestor, hopefully anyway.
Then assuming that things are good, the CA will issue the certificate.
And after the certificate is issued, it might be revoked before it expires for, you know, any number of reasons.
The CA needs to have not only the certificate requests, issued certificates, and revoked certificate lists, but it also needs to know where in the lifecycle any given certificate is.
The natural solution to this is a database and this is where the ODBC connection that I've talked about a few times comes into play.
By using an ODBC connection, cryptlib can be database agnostic.
The database is actually created in the certificate authority setup class's InitializeCertificateStore method.
The first few lines of code here are specific to a SQLite ODBC connection.
The file that the ODBC connection references as the database has to exist before it can be accessed, and it's this line that actually does the work.
Up until now we've used the file keyset type.
Here we're going to use an ODBC store keyset type, and this indicates to cryptlib that we're accessing the CA's database using ODBC.
And the KEYOPT_CREATE flag is what triggers cryptlib to create the tables that it uses within the database.
Issuing a certificate from a certificate request is a three step process in cryptlib.
The first step we need to do is to submit the request to the CA, meaning that the request is put into the database.
The second is to tell the CA to issue the certificate.
And the third step is to export the certificate out to a file so that it can be sent back to the requestor.
And we'll be doing all these steps in the CertificateAuthority class.

Submit a Certificate Signing Request to the CA The code that we'll be writing to submit a certificate signing request to the CA is in the CertificateAuthority class's SubmitCertificateRequest method.
And we pass in an instance of the CertificateAuthorityConfiguration and the CSR file name.
Now, admittedly, using the CertificateAuthorityConfiguration parameter is overkill because all we're taking from it is the ODBC name.
But I went this way for uniformity across the classes and methods.
When we submit a CSR to the CA, all we're doing is adding the CSR to the CA's database.
So the first thing we need to do is to open the CA database, again by using the ODBC_STORE keyset, and using the key option none so that we can write to it.
We need to import the certificate from the request file.
And even though the code is really short and simple, I've written another method in the certificate class to handle that for us.
To add the certificate request to the CA, we simply call cryptlib's add CA item function and pass it the database store and the certificate request handle.
The last thing we need to do is to clean up the cryptlib objects we've created, and we're done.

Issuing a Certificate The CSR has been submitted, the validation of identity has been done, allegedly, we are ready to issue a certificate.
To issue the certificate, we need two things, the CA key that will be used to sign the certificate, and the certificate signing request that we just submitted.
First we load the CA key.
I've already covered the code that gets a key from a file, so I'm just going to write the code quickly here and we'll move on.
Next, we'll get the request from the database.
So open the database, and I'm opening it with read only permissions.
I think I can actually hear you asking, but how are we going to get the issued certificate into the database? Well, when cryptlib issues a certificate, it writes that cert directory into the database so we don't have to worry about doing that.
When we need to get something from the CA database, we use the CAGetItem function, which needs the cryptlib handle to the database, the type of data that we want to get, and then type of key that we're going to use.
Now so far, we've been using a label that we set when creating keys in order to find those keys later.
With a certificate signing request, we're going to rely on the email address attached to the CSR in order to locate it.
So the key type that we're using is KEYID_EMAIL.
And lastly, we give it the email address for the CSR that we're looking for.
We have our CA key and our certificate signing request, so buckle up and get ready to issue a certificate from our CA.
That's it, we've issued a certificate.
I know, a bit anticlimactic, isn't it? The CACertManagement function is arguably one of the most powerful functions of the cryptlib API.
This function is used to perform certificate management operations and we just use it to issue a certificate, but we could also use it to revoke a certificate, issue a CRL, or expire a certificate.
The first parameter here is the action that we wanted to perform.
We're issuing a certificate, so we set it to the CERTACTION_ISSUE_CERT.
Then we gave it the cryptlib database handle, the caKey that we wanted to use to sign the certificate, and the CSR that the issued certificate is based off of.
So the CA has issued the certificate based off of our CSR, but as I mentioned, cryptlib has written the certificate directly into the CA database and we need to get that into a file so that we can return it to the requestor.
So we go back to CAGetItem to pull out a copy of the certificate.
This time we're telling cryptlib to return the certificate to us as a certificate chain, and we're pulling it out as a certificate chain so that the certificate can be validated back to the root CA certificate.
And we're still going to use the email address as the identifier for the cert we want.
Like we had before, we'll write the certificate to a file and clean up the cryptlib objects.
And that's it, we have a CA in place.
Now we're going to switch to the Duck Airline solution and put into practice all that we've talked about and the code that we have written so far in the course.

The Duck Airlines Project Welcome to Duck Airlines where we're proud to say that we have a 100% landing rate.
So proud, in fact, that our slogan is - Duck Airlines, we hit the ground every time.
As you may remember, we have a crisis aboard flight 657, which is now officially named Chicken Armageddon.
The good news is that we have secure messages flowing between flight 657 and flight operations, downgrading the catastrophic Chicken Armageddon to a simple Chicken Faux-Pas.
So sit back and relax as we journey back in time to create the proof of concept application that is the foundation for today's system that saved our feathers.
In this project, we're going to use the Bouncy Castle library.
Now we could have written it without using a third-party library, but the code that we would need to implement using only the .
NET libraries would really distract from our goal of understanding asymmetric cryptography, data encryption, and signatures.
Now I'm not going to cover how to use the Bouncy Castle library the way I did with the cryptlib library in the other part of this problem, because it's a complex library where there are often multiple ways to accomplish a task.
We would spend more time on Bouncy Castle than we would on the subject matter of this course.
I also chose not to use cryptlib in this project for two reasons, doing data encryption and signatures in cryptlib uses the same container concept that we used for the CA.
It's called enveloping.
And while it retains the benefit of API consistency and simplicity, there are a lot of steps that we would need to go through to do simple encryption and signatures, and we would wind up in a similar situation as using straight .
NET, where it would really distract us from understanding the higher level concepts.
I also want to fully separate the two parts of the project so that we can better simulate the real world where a certificate signing request is generated and sent to the CA for processing.
So open up the PluralsightDuckAirlines.
Cryptography solution, if it's not already, and we're going to get oriented with the project before we jump into the code.

Creating a Bouncy Castle Key Pair Before we can do any cryptographic operations, we, of course, need a key pair.
So in the key class, we have the GenerateKeyPair method, which receives its configuration information from the KeyConfiguration parameter.
Generating the key pair in Bouncy Castle requires a key pair generator.
We're using RSA key pairs, so we'll use the RsaKeyPairGenerator.
Now key pair generators require initialization, which is handled by the init method.
The init method takes a single key generator parameter's instance to pass in a secure random number generator and the key size to be generated, which in our case will be a 2048 bit key.
After we have initialized the key pair generator, we're free to generate a key pair.
We want to have our public key signed by the CA, so we will create a certificate signing request.
The method that we'll call to create the CSR requires four things, our private key, our name in distinguished name format, our public key, and any extensions that we want to have incorporated into the final signed certificate.
When we pass along our private key to sign our certificate request, the Bouncy Castle method doesn't accept the private key as it is.
We have to create a signature object that incorporates our private key, along with the algorithm that we want to use to sign our request.
And the way we go about creating the signature object is by creating an instance of Bouncy Castle's Asn1SignatureFactory method.
You'll hear ASN.
1 a lot in x.
509.
ASN stands for abstract syntax notation.
And it's a standardized way to describe data structures that can be serialized and deserialized, for that matter.
You'll most likely hear DER or BER used along with ASN.
1.
These are encoding rules that define how the ASN.
1 data will be encoded.
These are complex topics that could be courses on their own, and they're really outside the scope of what we're talking about here.
We will be signing our request using the SHA512WITHRSA encryption algorithm.
And we'll pass along to it our private key.
To create the distinguished name, we call the x.
509 name method, and there are a few overloads of this guy.
The one we're going to use takes as string representation of our DistinguishedName.
We've got everything we need, and let's create our CSR, which we do by calling the Pkcs10CertificationRequest method.
We talked about a couple of the other PKCS formats in earlier parts of the course.
Mostly PKCS 8 and PKCS 12, which deal with how to format and store private keys.
PKCS 10 just defines the certificate signing request message format.
We will create a new instance of the PKCS 10 certificate request method and pass along our signer distinguishedName, Public key, and since we aren't attaching any extensions, we'll just set the last parameter to null.
Our last task here is to write out the private key and our CSR to files.
We're going to use Bouncy Castle's PEM stream writer to accomplish this task, which is essentially the text format of keys and certificates.
The next part of what we're going to do here is to write our encryption and decryption and our sign and verify code.
And then after we have that written, we'll be ready to actually run our applications.

Encryption We have two pairs of cryptographic operations.
We have encryption and decryption, along with signing data and validating the signature of the data.
We're going to start with encryption decryption, and to decrypt data, we need to have encrypted data.
So we'll start with writing the encryption method first.
So open up the Cryptography class, and in here is the encryption method, which takes the unencrypted data and the certificate file name.
Now if you remember back to our conversation in the introducing the public key infrastructure module, we encrypt data with the public key of the recipient.
So the certificate being passed into us is the final name holding that public key.
Also, all of the cryptographic operations in Bouncy Castle take data in and return data as byte arrays.
So you'll see string to byte or byte to string conversions where we're dealing with string data.
Our first step in Bouncy Castle is to create an encryption engine.
To create an RSA engine, we create an instance of a PKCS1 encoder and provide it with an instance of the RsaEngine class.
PCKS1 being the standard that defines several aspects of the RSA keys.
When we initialize the encryption engine, it will require the public key, so we will read the certificate from the file specified by the certificate file name parameter, which we do by using an instance of the X509CertificateParser class.
More specifically, we will use the ReadCertificate method in the X509CertificateParser class, which requires a stream from which to read the data.
So we'll create a file stream to read the data from our certificate file.
To initialize the engine, we call the engine's Init method, which takes two parameters.
The first parameter is named forEncryption, which is a Boolean.
We're encrypting here, so we will set it to trust.
The second parameter is the public key that the engine will use, which we can get using the certificate class's GetPublicKey method.
Back in the public private key pair module, we talked about how the data to be, well, in this case encrypted, had to be broken down into blocks, and the size of those blocks is determined by the size of the key.
If you haven't watched it yet, it's definitely something that you might want to watch before we go on here.
So with a 2048 bit key, we're limited to working with 245 bytes of data.
If we have more than 245 bytes of data, we'll need to divide the data into 245 byte blocks, and then iterate through those blocks to encrypt the data.
To keep things simple in our project, we're going to use data that's less than 245 bytes long.
And to encrypt the data, we're going to call the encryption engine's ProcessBlock method, which needs the data to be encrypted as a byte array, the starting index where it should start processing the array, and finally, how many bytes it should include in this block.
So if we had, let's say, 600 bytes of data to process, we would have three iterations to go through, but, in this case, we've encrypted the entire block of data and can return it to the caller.
We're going to build on what

Decryption we just learned in the encrypt method to write the code to decrypt the data.
First, we're going to create an instance of an RSA engine, just like we did in the encrypt method.
The way that we're going to load the private key though is different and I've broken each step down into its own line of code so that the code doesn't get in the way of understanding what's going on here.
So, if you remember back when we generated the keys, we wrote the private key to the file using a PEM writer, which writes the key out to the file in text format.
So we'll read the text from the file into the rawKeyFromFile variable.
We need to provide that data to the PEM reader through a text reader.
So we'll create a new text reader via a StringReader class, and we'll name it rawKey.
So now we can create the PemReader and give it the rawKey text reader, and put them into the pemReader variable.
The last step to get the private key is to read the pemObject from the pemReader.
Since there are several types of data that can be written in PEM format, we need to cast the data to an AsymmetricCipherKeyPair.
We are now ready to initialize our decryptionEngine.
We will set the first parameter to false to let the RSA encryption engine know that we would like it to decrypt our data, and we will provide a private key to the engine.
Remember that the pemObject is a key pair type, even though we don't have a public key in the key pair, we still need to specify that we're getting the private key from the pemObject.
We know that the data is less than 254 bytes long, so we won't worry about iterating through the data block by block.
We just need to process the single block, convert it from bytes back into string format, and finally return the data to the caller.

Signing Data Between the encrypt and decrypt methods, we've already written most of the code that we'll need in order to write the Sign and Validate methods.
And of course, to validate a signature, we need a signature to validate.
So we'll write the Sign method first.
Our data is coming into us as a string, so we'll convert that over to a byte array for Bouncy Castle.
The code to read the private key is the same as the code in the decrypt method.
The way that Bouncy Castle does data signing is a bit different from the way it does cryptography.
Rather than creating an encryption engine, we create a signer by calling the SignerUtilities.
InitSigner method.
Any signature implementation will need to know which algorithm to use and the private key with which to sign the data.
The InitSigner method also needs to know two other things from us.
First, is a Boolean flag to tell it whether we're signing data or we want to validate a signature.
The other is an instance of the secure random class.
The first parameter is the algorithm, and we'll initialize a signer with the SHA1withRSA algorithm.
The next parameter is forSigning, which is pretty much the same as the forEncryption flag that we dealt with in the encryption decryption methods.
We're signing the data, so we'll set the parameter to true.
Next is the private key to use, and last is the instance of the SecureRandom class.
In order to sign the data, we have to provide the data to the signer in some way.
The signer has an internal cache that it uses to store the data that will be signed.
To get our data into the cache, we call the BlockUpdate method with our byte array and the part of the byte array that we want to add to the data cache.
And on that note, we're ready to generate the signature, which we do by calling the GenerateSignature method.
Before we pass it back, we'll base 64 encode the signature to make it easier to move around.
And that's it.
Of course, now that we have the signature, we're going to need to validate it.

Validating Signatures When we validate the signature, we not only need to know the data and the key, but also the signature with which we want to compare the signature that we generate.
So our ValidateSignature method takes three parameters rather than the usual two parameters we've seen in the other methods.
The code to get the public key to validate the signature is the same code that we covered in the encrypt method.
The signer code is the same as the code that we wrote in the sign method, with the exceptions of setting the forSigning parameter to false and passing the public key in rather than private key.
We, again, put the data into the cache, as we did in the Sign method.
Now, when we go to validate the signature, we need to provide it as a byte array, so let's go ahead and convert that.
We're now ready to call validate signature, which needs the signature to validate.
The last step, of course, is to return the result to the caller.
That's it, we're done writing the code.
Now let's go run it.

Running the PKI Project We've written a lot of code, but now is the fun part where we get to play with it.
I've written a help message for each of the applications that lists the commands and the parameters that each of the commands need.
So just type the name of the application and it will show up for you.
Now the first step here in the overall system is to install the certificate authority, which we do by using the install command line parameter.
So type ca install and wait a moment.
I edited out the actual time that it took to run this, but I think it was maybe like 5 to 10 seconds.
And over here, under the keys directory, we can see the keys for each CA.
I'm going to install them in the certificate store on this machine, basically so that we can see the certificate chain.
So obviously we will install the root CA first, and we install that to the trusted root certification authority's certificate store.
Okay, Next, Finish.
Since we're installing the certificate in the trusted root certification authority store, Windows is asking us, hey do you really want to do this? Yes we really want to do this.
So Yes, OK, and OK.
Let's check out the store here, and you will probably need to refresh the list in order for the newly installed certificate to show up.
Next is the policy CA certificate.
And we will install the policy CA certificate and all of the rest of the CA certificates, for that matter, in the intermediate certification authority store.
Since we're installing the certificates in a store that is not the trusted root certificate authority store, Windows isn't going to ask us if we really want to do this or not.
This certificate is a bit more interesting, so under the Certification Path tab, we can see an actual certificate chain here.
And back in the General tab, when we click on the Issuer Statement button, it takes us to the Trust Us CPS site.
I'm going to speed this up to Mach 1 here so that we don't have to spend a lot of time watching these certificates being installed.
So we have our CA installed, now we're going to go over to Duck Airlines and create keys.
We'll start with the flight operations key pair.
So type dac create, which will ask us for the information that it needs, starting with the distinguished name fields.
The private key password, and the file names for the private key and the certificate signing request.
Back over to Trust Us where we will submit our CSR to the Cleveland CA and tell it where our CSR file is.
Now that it's submitted, we can issue the certificate by typing ca issue from the Cleveland CA, the email address that's on the CSR, and finally, the file name that we want the CA to use for the certificate.
We'll repeat the steps for the Chicken Armageddon airplane.
Let's use a different CA this time.
We'll use Berlin.
So back over to Trust Us, submit the CSR and issue the certificate.
Our key pairs are now in place, but we need data to play with here.
So we'll write our message to operations here and save it as N657DA.
txt.
First we'll encrypt the data, so dac encrypt.
We're sending this from the airplane to flight operations, so we want to use flight operations public key to encrypt the message, the data that we are encrypting, and where we want it to be written.
If we open it up in Notepad here, it's weird, but it is encrypted.
So now the message has been received by flight operations and we'll decrypt it using flight operations private key.
Give it the encrypted file, and give it the file name we want it to use for the decrypted data.
And when we open the decrypt file in Notepad, we have the original message back.
Remember that we also want to sign the message so that flight operations can quickly validate the message is authentic and from flight 657.
So, we sign using the aircraft's private key, pass along the data file, and tell it the file name we want it to use when it writes down the signature.
Again, let's open it up in Notepad here, and it's a long one.
So let me just type it out in the console here.
And there we go.
Of course, the signature is useless if we don't verify it, so verify using the airplane's public key, the data that's been signed, and the signature to be validated.
And it's valid, yay.
Let's mess with the message and see what we get here.
And this time it's not valid, so I'll put it back to the way it was.
And everything is good to go again.
So there you go, a fully functional PKI implementation.

Summary We've put together a really good project here that will give you a foundation for experimenting and learning more about asymmetric cryptography.
And, as I said earlier, I'm hoping to continue to update the code with more functionality that you can use to explore other aspects of a PKI, like revoking certificates and getting a CRL.
I'll be putting those updates out over Twitter, but you can also look at duckairlines.
com, as I'll be putting updates there as well.

Summary Summary We've covered a lot of ground here, and you should have a good foundation of knowledge of PKI and asymmetric cryptography.
But there's always more to learn in any topic in software, and asymmetric crypto is no exception.
So if you're looking to dig deeper into PKI and cryptography, then here are a few ideas and resources to keep you going.
The library that we've used in this course is an excellent tool to continue learning through hands on coding, and the manual for the library gives good background, as well as the practical info on how to use it.
And, of course, Microsoft has thorough documentation on their crypto libraries and how to use them.
Now as of the time this course was published, this is the URL for their documentation.
If that URL changes, you should be able to search on either the term cryptography or using cryptography, or both for that matter, within Microsoft's site, and find the most recent documentation.
There are a number of open source CAs and CAs that provide free services.
And I've listed a couple of options here.
Commercial CAs will also usually have some useful documentation.
And that wraps up the course, so thank you for spending time with me to learn about asymmetric cryptography.
This is certainly a critical topic in the industry and I hope that I've been able to get you up to speed to not only understand asymmetric cryptography, but also to be able to sit down and actually write the code.

⚠️ **GitHub.com Fallback** ⚠️