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