Create csr modal

The CSR Modal allows users to generate a CSR code. Once the user
types in the necessary information to generate the CSR code, that modal
will then render the code and the user will be able to either copy the
code or download the code in a txt file.

Tested: loaded onto Witherspoon and able to view on certificate
management page.  Click on generate csr and type in necessary
(or any additional info), then click on generate CSR.  The CSR
code is then visible and is able to be copied or downloaded. In
error state in which CSR code is unable to generate, the modal
closes and an error toast message appears. FYI: Sometimes you
have to reboot system in order for csr to successfully generate.y

Signed-off-by: Mira Murali  <miramurali23@gmail.com>
Change-Id: I3cca09c494357496166164b5ee8ff99250ef981d
diff --git a/app/assets/icons/icon-warning.svg b/app/assets/icons/icon-warning.svg
new file mode 100644
index 0000000..6b6d822
--- /dev/null
+++ b/app/assets/icons/icon-warning.svg
@@ -0,0 +1,6 @@
+<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
+  <path d="M2.5 17L10 4l7.5 13z" fill="#ffb000" opacity=".4"/>
+  <path d="M10 1.4L.3 18.3h19.5L10 1.4zM10 4l7.5 13h-15L10 4z" fill="#ffb000"/>
+  <path d="M9.2 7.8v1.4l.4 3.5h.8l.4-3.5V7.8H9.2z"/>
+  <circle cx="10" cy="14.7" r=".8"/>
+</svg>
\ No newline at end of file
diff --git a/app/common/services/api-utils.js b/app/common/services/api-utils.js
index ba48a49..90a8cb3 100644
--- a/app/common/services/api-utils.js
+++ b/app/common/services/api-utils.js
@@ -1400,6 +1400,18 @@
                 return response.data;
               });
         },
+        createCSRCertificate: function(data) {
+          return $http({
+                   method: 'POST',
+                   url: DataService.getHost() +
+                       '/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR',
+                   withCredentials: true,
+                   data: data
+                 })
+              .then(function(response) {
+                return response.data['CSRString'];
+              });
+        },
         replaceCertificate: function(data) {
           return $http({
                    method: 'POST',
diff --git a/app/common/services/constants.js b/app/common/services/constants.js
index 37dd29f..9ac9b6c 100644
--- a/app/common/services/constants.js
+++ b/app/common/services/constants.js
@@ -24,11 +24,11 @@
         {
           'Description': 'HTTPS Certificate',
           'location':
-              '/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates'
+              '/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates/'
         },
         {
           'Description': 'LDAP Certificate',
-          'location': '/redfish/v1/AccountService/LDAP/Certificates'
+          'location': '/redfish/v1/AccountService/LDAP/Certificates/'
         }
       ],
       HOST_STATE_TEXT: {
@@ -102,6 +102,262 @@
         HOST_OFF: 1000 * 60 * 5,           // 5 mins
         HOST_OFF_IMMEDIATE: 1000 * 60 * 2  // 2 mins
       },
+      CERTIFICATE: {
+        KEY_BIT_LENGTH: [2048],
+        KEY_PAIR_ALGORITHM: ['EC', 'RSA'],
+        KEY_CURVE_ID: ['prime256v1', 'secp521r1', 'secp384r1']
+      },
+      COUNTRIES: [
+        {Name: 'Afghanistan', code: 'AF'},
+        {Name: 'Albania', code: 'AL'},
+        {Name: 'Algeria', code: 'DZ'},
+        {Name: 'American Samoa', code: 'AS'},
+        {Name: 'Andorra', code: 'AD'},
+        {Name: 'Angola', code: 'AO'},
+        {Name: 'Anguilla', code: 'AI'},
+        {Name: 'Antarctica', code: 'AQ'},
+        {Name: 'Antigua and Barbuda', code: 'AG'},
+        {Name: 'Argentina', code: 'AR'},
+        {Name: 'Armenia', code: 'AM'},
+        {Name: 'Aruba', code: 'AW'},
+        {Name: 'Australia', code: 'AU'},
+        {Name: 'Austria', code: 'AT'},
+        {Name: 'Azerbaijan', code: 'AZ'},
+        {Name: 'Bahamas, The', code: 'BS'},
+        {Name: 'Bahrain', code: 'BH'},
+        {Name: 'Bangladesh', code: 'BD'},
+        {Name: 'Barbados', code: 'BB'},
+        {Name: 'Belarus', code: 'BY'},
+        {Name: 'Belgium', code: 'BE'},
+        {Name: 'Belize', code: 'BZ'},
+        {Name: 'Benin', code: 'BJ'},
+        {Name: 'Bermuda', code: 'BM'},
+        {Name: 'Bhutan', code: 'BT'},
+        {Name: 'Bolivia', code: 'BO'},
+        {Name: 'Bonaire, Sint Eustatius and Saba', code: 'BQ'},
+        {Name: 'Bosnia and Herzegovina ', code: 'BA'},
+        {Name: 'Bostwana', code: 'BW'},
+        {Name: 'Bouvet Island', code: 'BV'},
+        {Name: 'Brazil', code: 'BR'},
+        {Name: 'British Indian Ocean Territory', code: 'IO'},
+        {Name: 'Brunei Darussalam ', code: 'BN'},
+        {Name: 'Bulgaria', code: 'BG'},
+        {Name: 'Burkina Faso', code: 'BF'},
+        {Name: 'Burundi', code: 'BI'},
+        {Name: 'Cabo Verde', code: 'CV'},
+        {Name: 'Cambodia', code: 'KH'},
+        {Name: 'Cameroon', code: 'CM'},
+        {Name: 'Canada', code: 'CA'},
+        {Name: 'Cayman Islands', code: 'KY'},
+        {Name: 'Central African Republic', code: 'CF'},
+        {Name: 'Chad', code: 'TD'},
+        {Name: 'Chile', code: 'CL'},
+        {Name: 'China', code: 'CN'},
+        {Name: 'Christmas Island ', code: 'CX'},
+        {Name: 'Cocos(Keeling) Islands', code: 'CC'},
+        {Name: 'Columbia', code: 'CO'},
+        {Name: 'Comoros', code: 'KM'},
+        {Name: 'Congo, The Democratic Republic of the', code: 'CD'},
+        {Name: 'Congo', code: 'CG'},
+        {Name: 'Cook Islands', code: 'CK'},
+        {Name: 'Costa Rica', code: 'CR'},
+        {Name: 'Croatia', code: 'HR'},
+        {Name: 'Cuba', code: 'CU'},
+        {Name: 'Curaçao', code: 'CW'},
+        {Name: 'Cyprus', code: 'CY'},
+        {Name: 'Czechia', code: 'CZ'},
+        {Name: 'Côte d\'Ivoire', code: 'CI'},
+        {Name: 'Denmark', code: 'DK'},
+        {Name: 'Djibouti', code: 'DJ'},
+        {Name: 'Dominica', code: 'DM'},
+        {Name: 'Dominican Republic', code: 'DO'},
+        {Name: 'Ecuador', code: 'EC'},
+        {Name: 'Egypt', code: 'EG'},
+        {Name: 'El Salvador', code: 'SV'},
+        {Name: 'Equatorial Guinea ', code: 'GQ'},
+        {Name: 'Eritrea', code: 'ER'},
+        {Name: 'Estonia', code: 'EE'},
+        {Name: 'Eswatini', code: 'SZ'},
+        {Name: 'Ethiopia', code: 'ET'},
+        {Name: 'Falkland Islands (Malvinas)', code: 'FK'},
+        {Name: 'Faroe Islands', code: 'FO'},
+        {Name: 'Fiji', code: 'FJ'},
+        {Name: 'Finland', code: 'FI'},
+        {Name: 'France', code: 'FR'},
+        {Name: 'French Guiana', code: 'GF'},
+        {Name: 'French Polynesia', code: 'PF'},
+        {Name: 'French Southern Territories', code: 'TF'},
+        {Name: 'Gabon', code: 'GA'},
+        {Name: 'Gambia, The', code: 'GM'},
+        {Name: 'Georgia', code: 'GE'},
+        {Name: 'Germany', code: 'DE'},
+        {Name: 'Ghana', code: 'GH'},
+        {Name: 'Gibraltar', code: 'GI'},
+        {Name: 'Greece', code: 'GR'},
+        {Name: 'Greenland', code: 'GL'},
+        {Name: 'Grenada', code: 'GD'},
+        {Name: 'Guadeloupe', code: 'GP'},
+        {Name: 'Guam', code: 'GU'},
+        {Name: 'Guatemala', code: 'GT'},
+        {Name: 'Guernsey', code: 'GG'},
+        {Name: 'Guinea', code: 'GN'},
+        {Name: 'Guinea-Bissau', code: 'GW'},
+        {Name: 'Guyana', code: 'GY'},
+        {Name: 'Haiti', code: 'HT'},
+        {Name: 'Heard Island and McDonald Islands', code: 'HM'},
+        {Name: 'Holy See', code: 'VA'},
+        {Name: 'Honduras', code: 'HN'},
+        {Name: 'Hong Kong', code: 'HK'},
+        {Name: 'Hungary', code: 'HU'},
+        {Name: 'Iceland', code: 'IS'},
+        {Name: 'India', code: 'IN'},
+        {Name: 'Indonesia', code: 'ID'},
+        {Name: 'Iran, Islamic Republic of', code: 'IR'},
+        {Name: 'Iraq', code: 'IQ'},
+        {Name: 'Ireland', code: 'IE'},
+        {Name: 'Isle of Man', code: 'IM'},
+        {Name: 'Israel', code: 'IL'},
+        {Name: 'Italy', code: 'IT'},
+        {Name: 'Jamaica', code: 'JM'},
+        {Name: 'Japan', code: 'JP'},
+        {Name: 'Jersey', code: 'JE'},
+        {Name: 'Jordan', code: 'JO'},
+        {Name: 'Kazakhstan', code: 'KZ'},
+        {Name: 'Kenya', code: 'KE'},
+        {Name: 'Kiribati', code: 'KI'},
+        {Name: 'Korea, Republic of', code: 'KR'},
+        {Name: 'Korea, Democratic People\'s Republic of', code: 'KP'},
+        {Name: 'Kuwait', code: 'KW'},
+        {Name: 'Kyrgyzstan', code: 'KG'},
+        {Name: 'Lao People\'s Democratic Republic', code: 'LA'},
+        {Name: 'Latvia', code: 'LV'},
+        {Name: 'Lebanon', code: 'LB'},
+        {Name: 'Lesotho', code: 'LS'},
+        {Name: 'Liberia', code: 'LR'},
+        {Name: 'Libya', code: 'LY'},
+        {Name: 'Liechtenstein', code: 'LI'},
+        {Name: 'Lithuania', code: 'LT'},
+        {Name: 'Luxembourg', code: 'LU'},
+        {Name: 'Macao', code: 'MO'},
+        {Name: 'Macedonia, The Former Yugoslav Republic of', code: 'MK'},
+        {Name: 'Madagascar', code: 'MG'},
+        {Name: 'Malawi', code: 'MW'},
+        {Name: 'Malaysia', code: 'MY'},
+        {Name: 'Maldives', code: 'MV'},
+        {Name: 'Mali', code: 'ML'},
+        {Name: 'Malta', code: 'MT'},
+        {Name: 'Marshall Islands', code: 'MH'},
+        {Name: 'Martinique', code: 'MQ'},
+        {Name: 'Mauritania', code: 'MR'},
+        {Name: 'Mauritius', code: 'MU'},
+        {Name: 'Mayotte', code: 'YT'},
+        {Name: 'Mexico', code: 'MX'},
+        {Name: 'Micronesia, Federated States of', code: 'FM'},
+        {Name: 'Moldova, Republic of', code: 'MD'},
+        {Name: 'Monaco', code: 'MC'},
+        {Name: 'Mongolia', code: 'MN'},
+        {Name: 'Montenegro', code: 'ME'},
+        {Name: 'Montserrat', code: 'MS'},
+        {Name: 'Morocco', code: 'MA'},
+        {Name: 'Mozambique', code: 'MZ'},
+        {Name: 'Myanmar', code: 'MM'},
+        {Name: 'Namibia', code: 'NA'},
+        {Name: 'Nauru', code: 'NR'},
+        {Name: 'Nepal', code: 'NP'},
+        {Name: 'Netherlands', code: 'NL'},
+        {Name: 'New Caledonia', code: 'NC'},
+        {Name: 'New Zealand', code: 'NZ'},
+        {Name: 'Nicaragua', code: 'NI'},
+        {Name: 'Niger', code: 'NE'},
+        {Name: 'Nigeria', code: 'NG'},
+        {Name: 'Niue', code: 'NU'},
+        {Name: 'Norfolk Island', code: 'NF'},
+        {Name: 'Northern Mariana Islands', code: 'MP'},
+        {Name: 'Norway', code: 'NO'},
+        {Name: 'Oman', code: 'OM'},
+        {Name: 'Pakistan', code: 'PK'},
+        {Name: 'Palau', code: 'PW'},
+        {Name: 'Palestine', code: 'PS'},
+        {Name: 'Panama', code: 'PA'},
+        {Name: 'Papua New Guinea', code: 'PG'},
+        {Name: 'Paraguay', code: 'PY'},
+        {Name: 'Peru', code: 'PE'},
+        {Name: 'Philippines', code: 'PH'},
+        {Name: 'Pitcairn', code: 'PN'},
+        {Name: 'Poland', code: 'PL'},
+        {Name: 'Portugal', code: 'PT'},
+        {Name: 'Puerto Rico', code: 'PR'},
+        {Name: 'Qatar', code: 'QA'},
+        {Name: 'Romania', code: 'RO'},
+        {Name: 'Russian Federation', code: 'RU'},
+        {Name: 'Rwanda', code: 'RW'},
+        {Name: 'Réunion', code: 'RE'},
+        {Name: 'Saint Barthélemy', code: 'BL'},
+        {Name: 'Saint Helena, Ascension and Tristan da Cunha', code: 'SH'},
+        {Name: 'Saint Kitts and Nevis ', code: 'KN'},
+        {Name: 'Saint Lucia', code: 'LC'},
+        {Name: 'Saint Martin', code: 'MF'},
+        {Name: 'Saint Pierre and Miquelon', code: 'PM'},
+        {Name: 'Saint Vincent and the Grenadines', code: 'VC'},
+        {Name: 'Samoa', code: 'WS'},
+        {Name: 'San Marino ', code: 'SM'},
+        {Name: 'Sao Tome and Principe', code: 'ST'},
+        {Name: 'Saudi Arabia', code: 'SA'},
+        {Name: 'Senegal', code: 'SN'},
+        {Name: 'Serbia', code: 'RS'},
+        {Name: 'Seychelles', code: 'SC'},
+        {Name: 'Sierra Leone', code: 'SL'},
+        {Name: 'Singapore', code: 'SG'},
+        {Name: 'Sint Maarten', code: 'SX'},
+        {Name: 'Slovakia', code: 'SK'},
+        {Name: 'Slovenia', code: 'SI'},
+        {Name: 'Solomon Islands', code: 'SB'},
+        {Name: 'Somalia', code: 'SO'},
+        {Name: 'South Africa ', code: 'ZA'},
+        {Name: 'South Georgia and the South Sandwich Islands', code: 'GS'},
+        {Name: 'South Sudan', code: 'SS'},
+        {Name: 'Spain', code: 'ES'},
+        {Name: 'Sri Lanka', code: 'LK'},
+        {Name: 'Sudan', code: 'SD'},
+        {Name: 'Suriname', code: 'SR'},
+        {Name: 'Svalbard and Jan Mayen', code: 'SJ'},
+        {Name: 'Sweden', code: 'SE'},
+        {Name: 'Switzerland', code: 'CH'},
+        {Name: 'Syrian Arab Republic', code: 'SY'},
+        {Name: 'Taiwan', code: 'TW'},
+        {Name: 'Tajikistan', code: 'TJ'},
+        {Name: 'Tanzania, United Republic of', code: 'TZ'},
+        {Name: 'Thailand', code: 'TH'},
+        {Name: 'Timor-Leste', code: 'TL'},
+        {Name: 'Togo', code: 'TG'},
+        {Name: 'Tokelau', code: 'TK'},
+        {Name: 'Tonga', code: 'TO'},
+        {Name: 'Trinidad and Tobago', code: 'TT'},
+        {Name: 'Tunisia', code: 'TN'},
+        {Name: 'Turkey', code: 'TR'},
+        {Name: 'Turkmenistan', code: 'TM'},
+        {Name: 'Turks and Caicos Islands', code: 'TC'},
+        {Name: 'Tuvalu', code: 'TV'},
+        {Name: 'Uganda', code: 'UG'},
+        {Name: 'Ukraine', code: 'UA'},
+        {Name: 'United Arab Emirates', code: 'AE'},
+        {Name: 'United Kingdom', code: 'GB'},
+        {Name: 'United States Minor Outlying Islands', code: 'UM'},
+        {Name: 'United States of America', code: 'US'},
+        {Name: 'Uruguay', code: 'UY'},
+        {Name: 'Uzbekistan', code: 'UZ'},
+        {Name: 'Vanuatu', code: 'VU'},
+        {Name: 'Venezuela', code: 'VE'},
+        {Name: 'Viet Nam', code: 'VN'},
+        {Name: 'Virgin Islands, British', code: 'VG'},
+        {Name: 'Virgin Islands, U.S', code: 'VI'},
+        {Name: 'Wallis and Futuna', code: 'WF'},
+        {Name: 'Western Sahara', code: 'EH'},
+        {Name: 'Yemen', code: 'YE'},
+        {Name: 'Zambia', code: 'ZM'},
+        {Name: 'Zimbabwe', code: 'ZW'},
+        {Name: 'Åland Islands', code: 'AX'}
+      ],
       MESSAGES: {
         POLL: {
           HOST_ON_TIMEOUT:
diff --git a/app/common/styles/base/buttons.scss b/app/common/styles/base/buttons.scss
index 6337b33..1e2b799 100644
--- a/app/common/styles/base/buttons.scss
+++ b/app/common/styles/base/buttons.scss
@@ -66,6 +66,11 @@
     width: auto;
     max-width: 100%;
   }
+
+  // Override for specific icons
+  .icon-add {
+    margin-right: 0;
+  }
 }
 
 /***
diff --git a/app/common/styles/elements/modals.scss b/app/common/styles/elements/modals.scss
index 450a26b..263d285 100644
--- a/app/common/styles/elements/modals.scss
+++ b/app/common/styles/elements/modals.scss
@@ -20,6 +20,8 @@
 
 .modal:not(.uib-modal) {
   width: auto;
+  min-width: 450px;
+  max-width: 960px;
   height: auto;
   left: 50%;
   top: 50%;
diff --git a/app/configuration/controllers/certificate-controller.html b/app/configuration/controllers/certificate-controller.html
index 89ea28f..faedce2 100644
--- a/app/configuration/controllers/certificate-controller.html
+++ b/app/configuration/controllers/certificate-controller.html
@@ -3,9 +3,10 @@
   <div class="row column">
     <h1>SSL certificates</h1>
   </div>
-  <div ng-repeat="certificate in certificates|filter:{isExpiring:true}" class="row column">
+  <div ng-repeat="certificate in certificates | filter:{isExpiring:true}" class="row column">
     <div class="small-12 alert alert-warning" role="alert">
-        <div class="icon__warning inline"></div> The uploaded {{certificate.Description}} is expiring in {{getDays(certificate.ValidNotAfter) === 0 ? 'less than one day!' : getDays(certificate.ValidNotAfter) + ' days!'}} Consider replacing it with a new certificate.
+      <icon aria-hidden="true" file="icon-warning.svg" /> The uploaded {{certificate.Description}} is expiring in {{getDays(certificate.ValidNotAfter) === 0 ? 'less than one
+      day!' : getDays(certificate.ValidNotAfter) + ' days!'}}. Consider replacing it with a new certificate.
     </div>
   </div>
   <div ng-repeat="certificate in certificates|filter:{isExpired:true}" class="row column">
@@ -14,12 +15,14 @@
     </div>
   </div>
   <div class="row column">
-    <button type="button" class="btn  btn-tertiary"
-      ng-disabled="availableCertificateTypes.length === 0"
-      ng-click="addCertificateModal=true">
-      <icon file="icon-plus.svg"></icon>
+    <button type="button" class="btn  btn-tertiary" ng-disabled="availableCertificateTypes.length === 0" ng-click="addCertificateModal=true">
+      <icon class="icon-add" file="icon-plus.svg"></icon>
       Add new certificate
     </button>
+    <button type="button" class="btn btn-tertiary" ng-click="addCSRModal=true">
+      <icon class="icon-add" file="icon-plus.svg"></icon>
+      Generate CSR
+    </button>
   </div>
   <div class="row column">
     <div class="small-12 certificate__table">
@@ -44,56 +47,246 @@
           </div>
         </div>
       </div>
-      <div ng-if="certificates.length < 1" class="empty__logs" >There have been no certificates added.</div>
+      <div ng-if="certificates.length < 1" class="empty__logs">There have been no certificates added.</div>
       <div ng-repeat="certificate in certificates">
-        <certificate cert="certificate" reload="loadCertificates()")></certificate>
+        <certificate cert="certificate" reload="loadCertificates()" )></certificate>
       </div>
     </div>
   </div>
   <section class="modal add__certificate__modal" aria-hidden="true" role="dialog" ng-class="{'active': addCertificateModal}">
-    <div class="page-header ">
-      <h3>Add new certificate</h3>
-    </div>
-    <div class="modal__content">
-      <form name="add__cert__form" id="add__cert__form" ng-class="{'submitted': submitted}">
-        <div class="row column">
+    <form name="add__cert__form" id="add__cert__form" ng-class="{'submitted': submitted}">
+      <div class="modal__content">
+        <button class="certificate__close-modal" ng-click="addCertificateModal = false; add__cert__form.$setUntouched()">
+          <icon aria-hidden="true" file="icon-close.svg">
+        </button>
+        <h2 class="page-header">Add new certificate</h2>
+        <div class="row column add-certificate__section ">
           <div class="small-12">
-          <label for="cert__type">Certificate type</label>
-          <select id="cert__type" name="cert__type" ng-model="newCertificate.selectedType" required>
-            <option class="courier-bold" ng-value="">Select an option</option>
-            <option class="courier-bold" ng-value="type" ng-repeat="type in availableCertificateTypes">{{type.Description}}</option>
-          </select>
-          <div ng-messages="add__cert__form.cert__type.$error" class="form-error" ng-class="{'visible' : add__cert__form.cert__type.$touched || submitted}">
-            <p ng-message="required">Field is required</p>
-          </div>
-          </div>
-        </div>
-        <div class="row column">
-          <div class="small-12">
-            <label class ="select__new-label" for="upload_cert_new">Certificate file</label>
-          </div>
-          <div class="row column file__upload">
-            <label for='upload_cert_new'>
-              <input name="upload_cert_new" id="upload_cert_new" type="file" file="newCertificate.file" class="hide"/>
-              <span class="btn btn-secondary select__new-button">Choose file</span>
-            </label>
-          </div>
-          <div class="row column">
-            <div ng-if="newCertificate.file" class="small-7 file__name">
-              <span>{{newCertificate.file.name}}</span>
-              <icon file="icon-close.svg"
-                ng-if="newCertificate.file.name"
-                ng-click="newCertificate.file = '';"
-                class="float-right"></icon>
+            <label for="cert__type">Certificate type</label>
+            <select id="cert__type" name="cert__type" ng-model="newCertificate.selectedType" required>
+              <option class="courier-bold" ng-value="">Select an option</option>
+              <option class="courier-bold" ng-value="type" ng-repeat="type in availableCertificateTypes">
+                {{type.Description}}</option>
+            </select>
+            <div ng-messages="add__cert__form.cert__type.$error" class="form-error" ng-class="{'visible' : add__cert__form.cert__type.$touched || submitted }">
+              <p ng-message="required">Field is required</p>
             </div>
           </div>
         </div>
-      </form>
-    </div>
-    <div class="modal__button-wrapper">
-      <button class="btn btn-secondary" ng-click="addCertificateModal = false; newCertificate={};add__cert__form.$setUntouched();">Cancel</button>
-      <button class="btn btn-primary" ng-class="{'disabled' : add__cert__form.$invalid || !newCertificate.file}" ng-click="submitted = true; uploadCertificate();">Save</button>
-    </div>
+        <div class="row column add-certificate__section">
+          <div class="small-12">
+            <label class="select__new-label" for="upload_cert_new">Certificate file</label>
+          </div>
+          <div class="row column file__upload add-certificate__section ">
+            <label for='upload_cert_new'>
+              <input name="upload_cert_new" id="upload_cert_new" type="file" file="newCertificate.file" class="hide" />
+              <span class="btn btn-secondary select__new-button">Choose file</span>
+            </label>
+          </div>
+          <div class="row column add-certificate__section ">
+            <div ng-if="newCertificate.file" class="small-7 file__name">
+              <span>{{newCertificate.file.name}}</span>
+              <icon file="icon-close.svg" ng-if="newCertificate.file.name" ng-click="newCertificate.file = '';" class="float-right"></icon>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="modal__button-wrapper">
+        <button class="btn btn-secondary" ng-click="addCertificateModal = false; newCertificate={};add__cert__form.$setUntouched();">Cancel</button>
+        <button class="btn btn-primary" ng-disabled="add__cert__form.$invalid || !newCertificate.file" ng-click="submitted = true; uploadCertificate();">Save</button>
+      </div>
+    </form>
   </section>
-  <div class="modal-overlay" tabindex="-1" ng-class="{'active': addCertificateModal}"></div>
-</div>
+
+  <section class="modal add-csr__modal" aria-hidden="true" role="dialog" ng-class="{'active': addCSRModal}">
+    <!--Close button for displaying CSR Code, we need a close button within form to reset form validation correctly-->
+    <button class="certificate__close-modal" ng-click="resetCSRModal();" ng-if="displayCSRCode==true">
+      <icon aria-hidden="true" file="icon-close.svg">
+    </button>
+
+    <!-- CSR Code display content-->
+
+    <div ng-if="displayCSRCode==true">
+      <h2 class="page-header">Certificate Signing Request (CSR)</h2>
+      <div class="modal__content add-csr__container">
+        <span id="csrCode" class="add-csr__container-csr-code">{{csrCode}}</span>
+      </div>
+      <div class="modal__button-wrapper">
+        <button class="btn btn-secondary" clipboard text="csrCode" on-copied="copySuccess(event)" on-error="copyfailed(err)">
+          <span ng-if="!copied">Copy</span>
+          <span ng-if="copied">
+            <icon aria-hidden="true" file="icon-check.svg"></icon>
+            <span>Copied</span>
+          </span>
+        </button>
+        <button class="btn btn-primary" ng-click="addCSRModal = false;">
+          <a ng-href="data:text/json;charset=utf-8,{{csrCode}}" download="csrCode.txt" class="add-csr__text-download">
+            Download</a>
+        </button>
+      </div>
+
+    </div>
+
+
+
+    <form name="add__csr__form" id="add__csr__form" novalidate ng-if="displayCSRCode==false">
+      <div class="modal__content add-csr__container">
+        <button class="certificate__close-modal" ng-click="resetCSRModal(); add__csr__form.$setUntouched()">
+          <icon aria-hidden="true" file="icon-close.svg">
+        </button>
+        <h2 class="page-header">Generate a Certificate Signing Request (CSR)</h2>
+        <div class="row">
+          <fieldset class="column medium-8 add-csr__section">
+            <legend class="add-csr__section-title">General</legend>
+            <div class="row">
+              <div class="column medium-6">
+                <label for="cert__type" class="add-csr__label">Certificate Type *</label>
+                <select class="add-csr__select" id="cert__type" name="cert__type" ng-model="newCSR.certificateCollection" required>
+                  <option class="courier-bold" ng-value="default" ng-model="selectOption">Select an option</option>
+                  <option class="courier-bold" ng-value="type" ng-repeat="type in allCertificateTypes">
+                    {{type.Description}}</option>
+                </select>
+                <div ng-messages="add__csr__form.cert__type.$error" class="form-error" ng-class="{'visible' : add__csr__form.cert__type.$touched}">
+                  <p ng-message="required">Field is required</p>
+                </div>
+              </div>
+              <div class="column medium-6">
+                <label for="countryCode" class="add-csr__label">Country *</label>
+                <select class="add-csr__select" id="countryCode" name="countryCode" ng-model="newCSR.countryCode" required>
+                  <option class="courier-bold" ng-value="" ng-model="selectOption">Select an option</option>
+                  <option class="courier-bold" ng-value="country" ng-repeat="country in countryList">{{country.Name}}
+                  </option>
+                </select>
+                <div ng-messages="add__csr__form.countryCode.$error" class="form-error" ng-class="{'visible' : add__csr__form.countryCode.$touched}">
+                  <p ng-message="required">Field is required</p>
+                </div>
+              </div>
+
+              <div class="column medium-6">
+                <label for="state" class="add-csr__label">State *</label>
+                <input class="add-csr__input" ng-model="newCSR.state" type="text" id="state" name="state" required></input>
+                <div ng-messages="add__csr__form.state.$error" class="form-error" ng-class="{'visible' : add__csr__form.state.$touched}">
+                  <p ng-message="required">Field is required</p>
+                </div>
+              </div>
+
+              <div class="column medium-6">
+                <label for="city" class="add-csr__label">City *</label>
+                <input class="add-csr__input" id="city" name="city" ng-model="newCSR.city" type="text" required></input>
+                <div ng-messages="add__csr__form.city.$error" class="form-error" ng-class="{'visible' : add__csr__form.city.$touched}">
+                  <p ng-message="required">Field is required</p>
+                </div>
+              </div>
+
+              <div class="column medium-6">
+                <label for="companyName" class="add-csr__label">Company Name *</label>
+                <input class="add-csr__input" type="text" ng-model="newCSR.organization" id="companyName" name="companyName" required></input>
+                <div ng-messages="add__csr__form.companyName.$error" class="form-error" ng-class="{'visible' : add__csr__form.companyName.$touched}">
+                  <p ng-message="required">Field is required</p>
+                </div>
+              </div>
+
+              <div class="column medium-6">
+                <label for="companyUnit" class="add-csr__label">Company Unit *</label>
+                <input class="add-csr__input" ng-model="newCSR.companyUnit" name="companyUnit" id="companyUnit" type="text" required></input>
+                <div ng-messages="add__csr__form.companyUnit.$error" class="form-error" ng-class="{'visible' : add__csr__form.companyUnit.$touched}">
+                  <p ng-message="required">Field is required</p>
+                </div>
+              </div>
+
+              <div class="column medium-6">
+                <label for="commonName" class="add-csr__label">Common Name *</label>
+                <input class="add-csr__input" ng-model="newCSR.commonName" name="commonName" type="text" id="commonName" required></input>
+                <div ng-messages="add__csr__form.commonName.$error" class="form-error" ng-class="{'visible' : add__csr__form.commonName.$touched}">
+                  <p ng-message="required">Field is required</p>
+                </div>
+              </div>
+
+              <div class="column medium-6">
+                <label for="challengePassword" class="add-csr__label">Challenge Password</label>
+                <input class="add-csr__input-no-validation" id="challengePassword" ng-model="newCSR.challengePassword" type="text"></input>
+              </div>
+
+              <div class="column medium-6">
+                <label for="contactPerson" class="add-csr__label">Contact Person</label>
+                <input class="add-csr__input-no-validation" id="contactPerson" ng-model="newCSR.contactPerson" type="text"></input>
+              </div>
+
+              <div class="column medium-6">
+                <label for="emailAddress" class="add-csr__label">Email Address</label>
+                <input class="add-csr__input-no-validation" id="emailAddress" ng-model="newCSR.emailAddress" type="text"></input>
+              </div>
+
+              <div class="column medium-6">
+                <div>
+                  <label id="alternate-name-label" for="alternateName" class="add-csr__label">Alternate Name</label>
+                  <input class="add-csr__input-no-validation" ng-model="newCSR.firstAlternativeName" id="alternateName" name="alternativeName"
+                    type="text"></input>
+                </div>
+                <div class="add-csr__additional-alt-names" ng-repeat="name in names">
+                  <input id="alternate-name-input-{{$index}}" aria-describedby="alternate-name-label" class="add-csr__input-no-validation"
+                    ng-model="name.Value" type="text"></input>
+                  <button aria-label="Delete alternate name field" aria-controls="alternate-name-input-{{$index}}" class="btn btn-tertiary add-csr__alt-name-delete-btn"
+                    ng-click="deleteOptionalRow($index)" ng-disabled="multiSelected">
+                    <icon aria-hidden="true" file="icon-trashcan.svg">
+                  </button>
+                </div>
+              </div>
+
+              <div class="column medium-6">
+                <button class="btn btn-tertiary add-csr__alt-name-add-btn" ng-click="addOptionalRow()">
+                  <icon file="icon-plus.svg"></icon>
+                  Add another alternate name
+                </button>
+              </div>
+            </div>
+          </fieldset>
+
+          <fieldset class="column medium-4 add-csr__section add-csr__section--border ">
+            <legend class="add-csr__section-title">Private key</legend>
+            <div class="add-csr__container-private-key">
+              <div class="add-csr__content-private-key">
+                <label for="keyPairAlgorithm" class="add-csr__label">Key Pair Algorithm *</label>
+                <select class="add-csr__select" ng-model="newCSR.keyPairAlgorithm" id="keyPairAlgorithm" name="keyPairAlgorithm" required>
+                  <option class="courier-bold" ng-value="" ng-model="selectOption">Select an option</option>
+                  <option class="courier-bold" ng-value="data" ng-repeat="data in keyPairAlgorithm">{{data}}</option>
+                </select>
+                <div ng-messages="add__csr__form.keyPairAlgorithm.$error" class="form-error" ng-class="{'visible' : add__csr__form.keyPairAlgorithm.$touched}">
+                  <p ng-message="required">Field is required</p>
+                </div>
+
+                <div ng-if="newCSR.keyPairAlgorithm == 'EC'">
+                  <label for="keyCurveId" class="add-csr__label">Key Curve ID</label>
+                  <select class="add-csr__select" ng-model="newCSR.keyCurveId" id="keyCurveId" name="keyCurveId" required>
+                    <option class="courier-bold" ng-value="">None</option>
+                    <option class="courier-bold" ng-value="data" ng-repeat="data in keyCurveId">{{data}}</option>
+                  </select>
+                  <div ng-messages="add__csr__form.keyCurveId.$error" class="form-error" ng-class="{'visible' : add__csr__form.keyCurveId.$touched}">
+                    <p ng-message="required">Field is required</p>
+                  </div>
+                </div>
+
+
+                <div ng-if="newCSR.keyPairAlgorithm =='RSA'">
+                  <label for="keyBitLength" class="add-csr__label">Key Bit Length *</label>
+                  <select class="add-csr__select" ng-model="newCSR.keyBitLength" id="keyBitLength" name="keyBitLength" required>
+                    <option class="courier-bold" ng-value="">Select an option</option>
+                    <option class="courier-bold" ng-value="data" ng-repeat="data in keyBitLength">{{data}}</option>
+                  </select>
+                  <div ng-messages="add__csr__form.keyBitLength.$error" class="form-error" ng-class="{'visible' : add__csr__form.keyBitLength.$touched}">
+                    <p ng-message="required">Field is required</p>
+                  </div>
+                </div>
+
+              </div>
+          </fieldset>
+          </div>
+        </div>
+        <div class="modal__button-wrapper">
+          <button class="btn btn-secondary" ng-click="resetCSRModal();add__csr__form.$setUntouched();">Cancel</button>
+          <button class="btn btn-primary" ng-click="csrSubmitted = true; getCSRCode();add__csr__form.$setUntouched();" ng-disabled="add__csr__form.$invalid">Generate CSR</button>
+        </div>
+      </div>
+    </form>
+  </section>
+  <div class="modal-overlay" tabindex="-1" ng-class="{'active': addCertificateModal || addCSRModal}"></div>
\ No newline at end of file
diff --git a/app/configuration/controllers/certificate-controller.js b/app/configuration/controllers/certificate-controller.js
index 7fa42a1..589035c 100644
--- a/app/configuration/controllers/certificate-controller.js
+++ b/app/configuration/controllers/certificate-controller.js
@@ -10,14 +10,25 @@
   'use strict';
 
   angular.module('app.configuration').controller('certificateController', [
-    '$scope', 'APIUtils', '$q', 'Constants', 'toastService',
-    function($scope, APIUtils, $q, Constants, toastService) {
+    '$scope', 'APIUtils', '$q', 'Constants', 'toastService', '$timeout',
+    function($scope, APIUtils, $q, Constants, toastService, $timeout) {
       $scope.loading = false;
       $scope.certificates = [];
       $scope.availableCertificateTypes = [];
+      $scope.allCertificateTypes = Constants.CERTIFICATE_TYPES;
       $scope.addCertificateModal = false;
+      $scope.addCSRModal = false;
       $scope.newCertificate = {};
+      $scope.newCSR = {};
       $scope.submitted = false;
+      $scope.csrSubmitted = false;
+      $scope.csrCode = '';
+      $scope.displayCSRCode = false;
+      $scope.keyBitLength = Constants.CERTIFICATE.KEY_BIT_LENGTH;
+      $scope.keyPairAlgorithm = Constants.CERTIFICATE.KEY_PAIR_ALGORITHM;
+      $scope.keyCurveId = Constants.CERTIFICATE.KEY_CURVE_ID;
+      $scope.countryList = Constants.COUNTRIES;
+
 
       $scope.loadCertificates = function() {
         $scope.certificates = [];
@@ -99,6 +110,96 @@
         }
       };
 
+      // add optional name
+      $scope.names = [];
+      $scope.addOptionalRow = function() {
+        $scope.names.push({Value: ''})
+      };
+
+      // remove optional name row
+      $scope.deleteOptionalRow = function(index) {
+        $scope.names.splice(index, 1);
+        if ($scope.names.length == 0) {
+          $scope.names = [];
+        }
+      };
+
+
+      // create a CSR object to send to the backend
+      $scope.getCSRCode = function() {
+        var addCSR = {};
+        let alternativeNames = $scope.names.map(name => name.Value);
+
+        // if user provided a first alternative name then push to alternative
+        // names array
+        $scope.newCSR.firstAlternativeName ?
+            alternativeNames.push($scope.newCSR.firstAlternativeName) :
+            $scope.newCSR.firstAlternativeName = '';
+
+
+        addCSR.CertificateCollection = {
+          '@odata.id': $scope.newCSR.certificateCollection.location
+        };
+        addCSR.CommonName = $scope.newCSR.commonName;
+        addCSR.ContactPerson = $scope.newCSR.contactPerson || '';
+        addCSR.City = $scope.newCSR.city;
+        addCSR.AlternativeNames = alternativeNames || [];
+        addCSR.ChallengePassword = $scope.newCSR.challengePassword || '';
+        addCSR.Email = $scope.newCSR.emailAddress || '';
+        addCSR.Country = $scope.newCSR.countryCode.code;
+        addCSR.Organization = $scope.newCSR.organization;
+        addCSR.OrganizationalUnit = $scope.newCSR.companyUnit;
+        addCSR.KeyCurveId = $scope.newCSR.keyCurveId || '';
+        addCSR.KeyBitLength = $scope.newCSR.keyBitLength
+        addCSR.KeyPairAlgorithm = $scope.newCSR.keyPairAlgorithm || '';
+        addCSR.State = $scope.newCSR.state;
+
+        APIUtils.createCSRCertificate(addCSR).then(
+            function(data) {
+              $scope.displayCSRCode = true;
+              $scope.csrCode = data;
+            },
+            function(error) {
+              $scope.addCSRModal = false;
+              toastService.error('Unable to generate CSR. Try again.');
+              console.log(JSON.stringify(error));
+            })
+      };
+
+      // resetting the modal when user clicks cancel/closes the
+      // modal
+      $scope.resetCSRModal = function() {
+        $scope.addCSRModal = false;
+        $scope.displayCSRCode = false;
+        $scope.newCSR.certificateCollection = $scope.selectOption;
+        $scope.newCSR.commonName = '';
+        $scope.newCSR.contactPerson = '';
+        $scope.newCSR.city = '';
+        $scope.names = [];
+        $scope.newCSR.challengePassword = '';
+        $scope.newCSR.emailAddress = '';
+        $scope.newCSR.countryCode = '';
+        $scope.newCSR.keyCurveId = '';
+        $scope.newCSR.firstAlternativeName = '';
+        $scope.newCSR.keyBitLength = $scope.selectOption;
+        $scope.newCSR.keyPairAlgorithm = $scope.selectOption;
+        $scope.newCSR.organization = '';
+        $scope.newCSR.companyUnit = '';
+        $scope.newCSR.state = '';
+      };
+
+      // copies the CSR code
+      $scope.copySuccess = function(event) {
+        $scope.copied = true;
+        $timeout(function() {
+          $scope.copied = false;
+        }, 5000);
+      };
+      $scope.copyFailed = function(err) {
+        console.log(JSON.stringify(err));
+      };
+
+
       var updateAvailableTypes = function(certificate) {
         // TODO: at this time only one of each type of certificate is allowed.
         // When this changes, this will need to be updated.
diff --git a/app/configuration/styles/certificate.scss b/app/configuration/styles/certificate.scss
index a113781..650465f 100644
--- a/app/configuration/styles/certificate.scss
+++ b/app/configuration/styles/certificate.scss
@@ -108,6 +108,14 @@
   background: $background-02;
 }
 
+
+.certificate__close-modal {
+  float: right;
+  position: relative;
+  bottom: 1rem;
+  left: 2rem;
+}
+
 .add__certificate__modal {
   select {
     margin-bottom: 0;
@@ -126,3 +134,107 @@
     padding: 0.5em;
   }
 }
+
+.add-certificate__section {
+  padding-left: 0;
+}
+
+// Combinator needed to match specificity
+// of default modal settings
+.modal.add-csr__modal {
+  width: 100%;
+  max-height: 100vh;
+  overflow-y: auto;
+  z-index: 1001;
+}
+
+.add-csr__section:first-of-type {
+  padding-left: 0;
+}
+
+.add-csr__section:last-of-type {
+  margin-top: 2rem;
+  padding-right: 0;
+
+  @media (min-width: 640px) {
+    margin-top: 0;
+  }
+}
+
+.add-csr__section-title {
+  margin-bottom: 1rem;
+  font-weight: 700;
+}
+
+.add-csr__section--border {
+  @media (min-width: 640px) {
+    padding-left: 2rem;
+    border-left: 1px solid $base-02--04;
+  }
+}
+
+.add-csr__label {
+  white-space: nowrap;
+  display: inline-block;
+}
+
+.add-csr__text-helper {
+  color: $base-02--02;
+  font-weight: 400;
+  font-size: 14px;
+  line-height: 1.2;
+  margin-bottom: .5em;
+}
+
+input.add-csr__input,
+select.add-csr__select {
+  width: 100%;
+  margin-bottom: 0;
+  max-height: none;
+  height: auto;
+}
+
+.select.add-csr__select  {
+  line-height: 1.15;
+}
+
+input.add-csr__input-no-validation {
+  margin-bottom: 1.7rem;
+}
+
+.add-csr__additional-alt-names {
+  display: flex;
+}
+
+.add-csr__alt-name-add-btn {
+  padding: 0;
+  @media (min-width: 640px) {
+    margin: 1.9rem 0;
+  }
+}
+
+.add-csr__alt-name-delete-btn {
+  width: 20px;
+  height: 30px;
+  padding: 0;
+
+  icon {
+    margin-right: 0;
+  }
+}
+
+.add-csr-code__header {
+  margin-top: 1em;
+}
+
+.add-csr__container-csr-code {
+  white-space: pre-wrap;
+}
+
+.add-csr__text-download {
+  color: $base-02--08;
+}
+
+select.add-csr__multiselect {
+  height: 14rem;
+}