xref: /openbmc/openbmc-test-automation/lib/certificate_utils.robot (revision 94041a34a992d9b5f6418a43e1cd5273a6d9f9b2)
1*** Settings ***
2Documentation  Certificate utilities keywords.
3
4Library        OperatingSystem
5Resource       rest_client.robot
6Resource       resource.robot
7
8*** Variables ***
9
10# Default wait sync time for certificate install and restart services.
11${wait_time}    30
12${keybit_length}  2048
13
14*** Keywords ***
15
16Install Certificate File On BMC
17    [Documentation]  Install certificate file in BMC using POST operation.
18    [Arguments]  ${uri}  ${status}=ok  &{kwargs}
19
20    # Description of argument(s):
21    # uri         URI for installing certificate file via Redfish
22    #             e.g. "/redfish/v1/AccountService/LDAP/Certificates".
23    # status      Expected status of certificate installation via Redfish
24    #             e.g. error, ok.
25    # kwargs      A dictionary of keys/values to be passed directly to
26    #             POST Request.
27
28    Initialize OpenBMC
29
30    ${headers}=  Create Dictionary  Content-Type=application/octet-stream
31    ...  X-Auth-Token=${XAUTH_TOKEN}
32    Set To Dictionary  ${kwargs}  headers  ${headers}
33
34    ${resp}=  POST On Session  openbmc  ${uri}  &{kwargs}  expected_status=any
35    ${cert_id}=  Set Variable If  '${resp.status_code}' == '${HTTP_OK}'  ${resp.json()["Id"]}  -1
36
37    IF  '${status}' == 'ok'
38        Should Be Equal As Strings  ${resp.status_code}  ${HTTP_OK}
39    ELSE IF  '${status}' == 'error'
40        Should Be Equal As Strings  ${resp.status_code}  ${HTTP_INTERNAL_SERVER_ERROR}
41    END
42
43    Delete All Sessions
44
45    RETURN  ${cert_id}
46
47
48Get Certificate Content From BMC Via Openssl
49    [Documentation]  Get certificate content from BMC via openssl.
50
51    Check If Openssl Tool Exist
52
53    ${openssl_cmd}=  Catenate
54    ...  timeout 10  openssl s_client -connect ${OPENBMC_HOST}:${HTTPS_PORT} -showcerts
55    ${output}=  Run  ${openssl_cmd}
56
57    ${result}=  Fetch From Left
58    ...  ${output}  -----END CERTIFICATE-----
59    ${result}=  Fetch From Right  ${result}  -----BEGIN CERTIFICATE-----
60    RETURN  ${result}
61
62
63Get Certificate File Content From BMC
64    [Documentation]  Get required certificate file content from BMC.
65    [Arguments]  ${cert_type}=Client
66
67    # Description of argument(s):
68    # cert_type      Certificate type (e.g. "Client" or "CA").
69
70    ${certificate}  ${stderr}  ${rc}=  Set Variable If  '${cert_type}' == 'Client'
71    ...    BMC Execute Command  cat /etc/nslcd/certs/cert.pem
72
73    RETURN  ${certificate}
74
75
76Generate Certificate File Via Openssl
77    [Documentation]  Create certificate file via openssl with required content
78    ...              and returns its path.
79    [Arguments]  ${cert_format}  ${time}=365  ${cert_dir_name}=certificate_dir
80
81    # Description of argument(s):
82    # cert_format          Certificate file format
83    #                      e.g. Valid_Certificate_Empty_Privatekey.
84    # time                 Number of days to certify the certificate for.
85    # cert_dir_name        The name of the sub-directory where the certificate
86    #                      is stored.
87
88    Check If Openssl Tool Exist
89
90    ${openssl_cmd}=  Catenate  openssl req -x509 -sha256 -newkey rsa:${keybit_length}
91    ...  ${SPACE}-nodes -days ${time}
92    ...  ${SPACE}-keyout ${cert_dir_name}/cert.pem -out ${cert_dir_name}/cert.pem
93    ...  ${SPACE}-subj "/O=XYZ Corporation /CN=www.xyz.com"
94
95    ${rc}  ${output}=  Run And Return RC and Output  ${openssl_cmd}
96    Should Be Equal  ${rc}  ${0}  msg=${output}
97    OperatingSystem.File Should Exist
98    ...  ${EXECDIR}${/}${cert_dir_name}${/}cert.pem
99
100    ${file_content}=  OperatingSystem.Get File
101    ...  ${EXECDIR}${/}${cert_dir_name}${/}cert.pem
102    ${result}=  Fetch From Left  ${file_content}  -----END CERTIFICATE-----
103    ${cert_content}=  Fetch From Right  ${result}  -----BEGIN CERTIFICATE-----
104
105    ${result}=  Fetch From Left  ${file_content}  -----END PRIVATE KEY-----
106    ${private_key_content}=  Fetch From Right  ${result}  -----BEGIN PRIVATE KEY-----
107
108    ${cert_data}=
109    ...  Set Variable If  '${cert_format}' == 'Valid Certificate Valid Privatekey'
110    ...  OperatingSystem.Get File  ${EXECDIR}${/}${cert_dir_name}${/}cert.pem
111    ...  ELSE IF  '${cert_format}' == 'Empty Certificate Valid Privatekey'
112    ...  Remove String  ${file_content}  ${cert_content}
113    ...  ELSE IF  '${cert_format}' == 'Valid Certificate Empty Privatekey'
114    ...  Remove String  ${file_content}  ${private_key_content}
115    ...  ELSE IF  '${cert_format}' == 'Empty Certificate Empty Privatekey'
116    ...  Remove String  ${file_content}  ${cert_content}  ${private_key_content}
117    ...  ELSE IF  '${cert_format}' == 'Expired Certificate' or '${cert_format}' == 'Not Yet Valid Certificate'
118    ...  OperatingSystem.Get File  ${EXECDIR}${/}${cert_dir_name}${/}cert.pem
119    ...  ELSE IF  '${cert_format}' == 'Valid Certificate'
120    ...  Remove String  ${file_content}  ${private_key_content}
121    ...  -----BEGIN PRIVATE KEY-----  -----END PRIVATE KEY-----
122    ...  ELSE IF  '${cert_format}' == 'Empty Certificate'
123    ...  Remove String  ${file_content}  ${cert_content}
124    ...  ${private_key_content}  -----BEGIN PRIVATE KEY-----
125    ...  -----END PRIVATE KEY-----
126
127    ${random_name}=  Generate Random String  8
128    ${cert_name}=  Catenate  SEPARATOR=  ${random_name}  .pem
129    Create File  ${cert_dir_name}/${cert_name}  ${cert_data}
130
131    RETURN  ${EXECDIR}${/}${cert_dir_name}${/}${cert_name}
132
133
134Get Certificate Content From File
135    [Documentation]  Get certificate content from certificate file.
136    [Arguments]  ${cert_file_path}
137
138    # Description of argument(s):
139    # cert_file_path  Downloaded certificate file path.
140
141    ${file_content}=  OperatingSystem.Get File  ${cert_file_path}
142    ${result}=  Fetch From Left  ${file_content}  -----END CERTIFICATE-----
143    ${result}=  Fetch From Right  ${result}  -----BEGIN CERTIFICATE-----
144    RETURN  ${result}
145
146
147Check If Openssl Tool Exist
148    [Documentation]  Check if openssl tool installed or not.
149
150    ${rc}  ${output}=  Run And Return RC and Output  which openssl
151    Should Not Be Empty  ${output}  msg=Openssl tool not installed.
152
153
154Verify Certificate Visible Via OpenSSL
155    [Documentation]  Checks if given certificate is visible via openssl's showcert command.
156    [Arguments]  ${cert_file_path}
157
158    # Description of argument(s):
159    # cert_file_path           Certificate file path.
160
161    ${cert_file_content}=  OperatingSystem.Get File  ${cert_file_path}
162    ${openssl_cert_content}=  Get Certificate Content From BMC Via Openssl
163    Should Contain  ${cert_file_content}  ${openssl_cert_content}
164
165
166Delete All CA Certificate Via Redfish
167    [Documentation]  Delete all CA certificate via Redfish.
168    ${cert_list}=  Redfish_Utils.Get Member List  /redfish/v1/Managers/${MANAGER_ID}/Truststore/Certificates
169    FOR  ${cert}  IN  @{cert_list}
170      Redfish.Delete  ${cert}  valid_status_codes=[${HTTP_NO_CONTENT}]
171      Log To Console  Wait Time started in seconds ${wait_time}
172      Sleep  ${wait_time}s
173    END
174
175
176Delete Certificate Via BMC CLI
177    [Documentation]  Delete certificate via BMC CLI.
178    [Arguments]  ${cert_type}
179
180    # Description of argument(s):
181    # cert_type           Certificate type (e.g. "Client" or "CA").
182
183    ${certificate_file_path}  ${certificate_service}  ${certificate_uri}=
184    ...  Set Variable If  '${cert_type}' == 'Client'
185    ...    Set Variable  /etc/nslcd/certs/cert.pem  phosphor-certificate-manager@nslcd.service
186    ...    ${REDFISH_LDAP_CERTIFICATE_URI}
187    ...  ELSE IF  '${cert_type}' == 'CA'
188    ...    Set Variable  ${ROOT_CA_FILE_PATH}  phosphor-certificate-manager@authority.service
189    ...    ${REDFISH_CA_CERTIFICATE_URI}
190
191    ${file_status}  ${stderr}  ${rc}=  BMC Execute Command
192    ...  [ -f ${certificate_file_path} ] && echo "Found" || echo "Not Found"
193
194    Return From Keyword If  "${file_status}" != "Found"
195    BMC Execute Command  rm ${certificate_file_path}
196    BMC Execute Command  systemctl restart ${certificate_service}
197    BMC Execute Command  systemctl daemon-reload
198    Wait Until Keyword Succeeds  1 min  10 sec  Redfish.Get  ${certificate_uri}/1
199    ...  valid_status_codes=[${HTTP_NOT_FOUND}, ${HTTP_INTERNAL_SERVER_ERROR}]
200
201
202Replace Certificate Via Redfish
203    [Documentation]  Test 'replace certificate' operation in the BMC via Redfish.
204    [Arguments]  ${cert_type}  ${cert_format}  ${expected_status}
205
206    # Description of argument(s):
207    # cert_type           Certificate type (e.g. "Server" or "Client").
208    # cert_format         Certificate file format
209    #                     (e.g. Valid_Certificate_Valid_Privatekey).
210    # expected_status     Expected status of certificate replace Redfish
211    #                     request (i.e. "ok" or "error").
212
213    # Install certificate before replacing client or CA certificate.
214    ${cert_id}=  Set Variable If  '${cert_type}' == 'Client'
215    ...    Install And Verify Certificate Via Redfish  ${cert_type}  Valid Certificate Valid Privatekey  ok
216    ...  ELSE IF  '${cert_type}' == 'CA'
217    ...    Install And Verify Certificate Via Redfish  ${cert_type}  Valid Certificate  ok
218
219    ${cert_file_path}=  Generate Certificate File Via Openssl  ${cert_format}
220
221    ${bytes}=  OperatingSystem.Get Binary File  ${cert_file_path}
222    ${file_data}=  Decode Bytes To String  ${bytes}  UTF-8
223
224    IF  '${cert_format}' == 'Expired Certificate'
225        Modify BMC Date  future
226    ELSE IF  '${cert_format}' == 'Not Yet Valid Certificate'
227        Modify BMC Date  old
228    END
229
230    ${certificate_uri}=  Set Variable If
231    ...  '${cert_type}' == 'Server'  ${REDFISH_HTTPS_CERTIFICATE_URI}/1
232    ...  '${cert_type}' == 'Client'  ${REDFISH_LDAP_CERTIFICATE_URI}/1
233    ...  '${cert_type}' == 'CA'  ${REDFISH_CA_CERTIFICATE_URI}/${cert_id}
234
235    ${certificate_dict}=  Create Dictionary  @odata.id=${certificate_uri}
236    ${payload}=  Create Dictionary  CertificateString=${file_data}
237    ...  CertificateType=PEM  CertificateUri=${certificate_dict}
238
239    ${expected_resp}=  Set Variable If  '${expected_status}' == 'ok'  ${HTTP_OK}, ${HTTP_NO_CONTENT}
240    ...  '${expected_status}' == 'error'  ${HTTP_NOT_FOUND}, ${HTTP_INTERNAL_SERVER_ERROR}, ${HTTP_BAD_REQUEST}
241    ${resp}=  redfish.Post  /redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate
242    ...  body=${payload}  valid_status_codes=[${expected_resp}]
243
244    ${cert_file_content}=  OperatingSystem.Get File  ${cert_file_path}
245    ${bmc_cert_content}=  redfish_utils.Get Attribute  ${certificate_uri}  CertificateString
246
247    IF  '${expected_status}' == 'ok'
248        Should Contain  ${cert_file_content}  ${bmc_cert_content}
249    ELSE
250        Should Not Contain  ${cert_file_content}  ${bmc_cert_content}
251    END
252
253Install And Verify Certificate Via Redfish
254    [Documentation]  Install and verify certificate using Redfish.
255    [Arguments]  ${cert_type}  ${cert_format}  ${expected_status}  ${delete_cert}=${True}
256
257    # Description of argument(s):
258    # cert_type           Certificate type (e.g. "Client" or "CA").
259    # cert_format         Certificate file format
260    #                     (e.g. "Valid_Certificate_Valid_Privatekey").
261    # expected_status     Expected status of certificate replace Redfish
262    #                     request (i.e. "ok" or "error").
263    # delete_cert         Certificate will be deleted before installing if this True.
264
265    IF  '${cert_type}' == 'CA' and '${delete_cert}' == '${True}'
266        Delete All CA Certificate Via Redfish
267    ELSE IF  '${cert_type}' == 'Client' and '${delete_cert}' == '${True}'
268        Delete Certificate Via BMC CLI  ${cert_type}
269    END
270
271    ${cert_file_path}=  Generate Certificate File Via Openssl  ${cert_format}
272    ${bytes}=  OperatingSystem.Get Binary File  ${cert_file_path}
273    ${file_data}=  Decode Bytes To String  ${bytes}  UTF-8
274
275    ${certificate_uri}=  Set Variable If
276    ...  '${cert_type}' == 'Client'  ${REDFISH_LDAP_CERTIFICATE_URI}
277    ...  '${cert_type}' == 'CA'  ${REDFISH_CA_CERTIFICATE_URI}
278
279    IF  '${cert_format}' == 'Expired Certificate'
280        Modify BMC Date  future
281    ELSE IF  '${cert_format}' == 'Not Yet Valid Certificate'
282        Modify BMC Date  old
283    END
284
285    ${cert_id}=  Install Certificate File On BMC  ${certificate_uri}  ${expected_status}  data=${file_data}
286    Logging  Installed certificate id: ${cert_id}
287
288    # Adding delay after certificate installation.
289    # Lesser wait timing causes bmcweb to restart quickly and breaks the web services.
290    Log To Console  Wait Time started in seconds ${wait_time}
291    Sleep  ${wait_time}s
292
293    ${cert_file_content}=  OperatingSystem.Get File  ${cert_file_path}
294    ${bmc_cert_content}=  Set Variable If  '${expected_status}' == 'ok'  redfish_utils.Get Attribute
295    ...  ${certificate_uri}/${cert_id}  CertificateString
296
297    IF  '${expected_status}' == 'ok'  Should Contain  ${cert_file_content}  ${bmc_cert_content}
298    RETURN  ${cert_id}
299
300
301Modify BMC Date
302    [Documentation]  Modify date in BMC.
303    [Arguments]  ${date_set_type}=current
304
305    # Description of argument(s):
306    # date_set_type    Set BMC date to a current, future, old date by 375 days.
307    #                  current - Sets date to local system date.
308    #                  future - Sets to a future date from current date.
309    #                  old - Sets to a old date from current date.
310
311    Redfish Power Off  stack_mode=skip
312    ${current_date_time}=  Get Current Date
313    ${new_time}=  Set Variable If  '${date_set_type}' == 'current'  ${current_date_time}
314    ...  ELSE IF  '${date_set_type}' == 'future'
315    ...  Add Time To Date  ${current_date_time}  375 days
316    ...  ELSE IF  '${date_set_type}' == 'old'
317    ...  Subtract Time From Date  ${current_date_time}  375 days
318
319    # Enable manual mode.
320    Redfish.Patch  ${REDFISH_NW_PROTOCOL_URI}
321    ...  body={'NTP':{'ProtocolEnabled': ${False}}}
322    ...  valid_status_codes=[${HTTP_OK}, ${HTTP_NO_CONTENT}]
323
324    # Change date format to 2024-03-07T07:58:50+00:00 from 2024-03-07 07:58:50.000.
325    ${new_time_format}=  Convert Date  ${new_time}  result_format=%Y-%m-%dT%H:%M:%S+00:00
326
327    # NTP network takes few seconds to restart.
328    Wait Until Keyword Succeeds  30 sec  10 sec
329    ...  Redfish.Patch  ${REDFISH_BASE_URI}Managers/${MANAGER_ID}  body={'DateTime': '${new_time_format}'}
330    ...  valid_status_codes=[${HTTP_OK}, ${HTTP_NO_CONTENT}]
331