It’s probably no secret that generating a CSR on the WLC controller so far has not been “effective” because such a signed device certificate, intended for example for GUI access, still generated a certificate error. This was due to the fact that some browsers, like Google Chrome, require the name present in the URL to be in the SAN (Subject Alternative Name) fields in order to trust the certificate.
If I wanted to add a Subject Alternate Name, it was not possible on Cisco IOS XE versions before 17.8.1 due to Cisco bug ID CSCvt15177
Therefore, so far I have been generating the certificate for WLC using openssl. However, recently, as I had to configure WLC from scratch with software 17.9.4, I took this opportunity and correctly created a CSR on the controller itself. How I did it, I describe below.

We have to start the entire process by generating RSA keys. RSA keys are generated to enable secure communication and data encryption by creating a pair of cryptographic keys – a public key for encryption and a private key for decryption – providing confidentiality and data integrity in digital communication.
In order to generate keys on the wireless controller, we can do it from the GUI in the following easy way:
Configuration > Security > PKI Management > Key Pair Generation > + Add
Fill in the fields according to your needs, remembering to select the option: Key Exportable

Then, having generated the keys, we can proceed to create a CSR. The CSR (Certificate Signing Request) is a cryptographic file generated by an entity seeking an SSL/TLS certificate, containing their public key and essential information.
Generating the CSR will be done this time from the command line because we are interested in creating a CSR that will include subject-alt-name information (SAN field). CLI configuration:
WLC(config)#crypto pki trustpoint WLC_MGMT_WEB
WLC(ca-trustpoint)#enrollment terminal pem
WLC(ca-trustpoint)#revocation-check none
WLC(ca-trustpoint)#subject-name C=<Country Name (2 letter code)>, ST=<State or Province Name (full name)>, L=<Locality Name (eg, city)>, O=<Organization Name (eg, company)>, OU=<organization unit>, CN=<Common Name (e.g. server FQDN or YOUR name)>
WLC(ca-trustpoint)#rsakeypair <key name>
WLC(ca-trustpoint)#subject-alt-name <FQDNs>
WLC(ca-trustpoint)#exitRemark:
The trustpoint is what links a certificate to a specific service. There are two main types of trustpoints: web administration and web authentication.
All that remains is to start the certificate enrollment.
WLC(config)#crypto pki enroll WLC_MGMT_WEBIf we want the WLC to be accessible by IP address, then when generating the certificate, we must clearly indicate this and then provide the IP address.
% Include an IP address in the subject name? [no]: yes
Enter Interface name or IP Address[]: <ip address>
Display Certificate Request to terminal? [yes/no]: yes
Certificate Request follows:
-----BEGIN CERTIFICATE REQUEST-----
<Certificate Request>
-----END CERTIFICATE REQUEST-----
---End - This line not part of the certificate request---
Redisplay enrollment request? [yes/no]: no
Copy the displayed Certificate Request and save it into a text editor and save the CSR. The full string needs to be sent to the CA to get it signed.
When we receive the signed certificate, we need to authenticate our certificate issuer. As my certificate is signed by a multi-level CA, I need to take further action, but no worries, it’s all described below.
In the scenario where multiple authorization levels exist, a new trustpoint is required for every additionnal CA level. In my case, I have one intermediate CA and one Root CA, that I need 2 trustpoints: the one already created and a new one, containing the Root CA certificate.
- Creating a new Trustpoint for RootCA
WLC(config)#crypto pki trustpoint RootCA
WLC(ca-trustpoint)#enrollment terminal
WLC(ca-trustpoint)#chain-validation stop
WLC(ca-trustpoint)#revocation-check none
WLC(ca-trustpoint)#exit
WLC(config)#crypto pki authenticate RootCA
Enter the base 64 encoded CA certificate.
End with a blank line or the word "quit" on a line by itself
-----BEGIN CERTIFICATE-----
<Root CA certificate>
-----END CERTIFICATE-----
Certificate has the following attributes:
Fingerprint MD5: <output ommitted>
Fingerprint SHA1: <output ommitted>
% Do you accept this certificate? [yes/no]: yes
Trustpoint CA certificate accepted.
% Certificate successfully imported2. Referencing the trustpoint that contains the next level of certifcation (RootCA) and authenticating our certificate issuer
WLC(config)#crypto pki trustpoint WLC_MGMT_WEB
WLC(ca-trustpoint)#chain-validation continue RootCA
WLC(config)#crypto pki authenticate WLC_MGMT_WEB
Enter the base 64 encoded CA certificate.
End with a blank line or the word "quit" on a line by itself
-----BEGIN CERTIFICATE-----
<Intermediate CA certificate>
-----END CERTIFICATE-----
Certificate has the following attributes:
Fingerprint MD5: <output ommitted>
Fingerprint SHA1: <output ommitted>
Certificate validated - Signed by existing trustpoint CA certificate.
Trustpoint CA certificate accepted.
% Certificate successfully importedAt the very end, all that remains is to add the device certificate that has been provided to us.
WLC(config)#crypto pki import WLC_MGMT_WEB certificate
Enter the base 64 encoded certificate.
End with a blank line or the word "quit" on a line by itself
-----BEGIN CERTIFICATE-----
< device certificate >
-----END CERTIFICATE-----
% Router Certificate successfully importedAt this point the device certificate is imported in the 9800 WLC along with all CA(s) and the certificate is now ready to be used. Since my certificate is used for GUI access, the procedure looks as follows.
WLC(config)#ip http secure-trustpoint WLC_MGMT_WEB
WLC(config)#no ip http secure-server
WLC(config)#ip http secure-serverSummary
Undoubtedly, the fixed bug, which so far prevented the correct creation of a CSR, has been fixed, and the process itself is definitely easier and faster than the openssl I used before. I recommend everyone to use the above instruction, especially since the recommended version currently on WLC is 17.9.4, which generates CSR without any problems, as I proved in the above post.