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