General Information
So what we basically want to do - we encrypt the email with the user public ceritifcate (the user is the our TO-Recipient of the email)
to encrypt emails we would need to override those interface methods:
IF_BADI_SMIME_EMAIL~CERTIFICATE_RETRIEVAL
IF_BADI_SMIME_EMAIL~CERTIFICATE_SELECTION
Note, that this methods are called after emails where pickuped from the mail queue
Implementation
If we get the user certificate, we store this in it_certificates
and then select it for the encrpytion.
So our Method IF_BADI_SMIME_EMAIL~CERTIFICATE_SELECTION.
would be like this:
method IF_BADI_SMIME_EMAIL~CERTIFICATE_SELECTION.
DATA:
lt_certificates TYPE if_badi_smime_email=>tt_certificates_x509.
lt_certificates = it_certificates.
" Filter out unsuitable certificates by some default criteria
CALL METHOD default_filter
CHANGING
ct_certificates = lt_certificates.
" When only one certificate is left, it is used, otherwise error
CASE lines( lt_certificates ).
WHEN 0.
RAISE EXCEPTION TYPE cx_smime_crypto
EXPORTING
textid = cx_smime_crypto=>certificate_not_found
email = if_email.
WHEN 1.
READ TABLE lt_certificates INTO ro_certificate INDEX 1.
WHEN OTHERS.
RAISE EXCEPTION TYPE cx_smime_crypto
EXPORTING
textid = cx_smime_crypto=>certificate_ambiguous
email = if_email.
ENDCASE.
endmethod.
now let's see how we can retrieve the certificate
Method 1 - get certificate from the STRUST Adress Book
method IF_BADI_SMIME_EMAIL~CERTIFICATE_RETRIEVAL.
* enhanced method to retrieve certificates form Address-book or LDAP server.
*
* PARAMETERS:
* IF_MAIL - email address of the receiver. For that email a public certificate should be retrieved, to
* encrypt email body.
*
DATA:
l_strustemail TYPE strustemail, " trust mail for address book, tmp variable
lt_strustcertificates TYPE strustcerttab, " list of certificates
CLEAR et_certificates.
* ===
* Find user in address book.
*
" Format change for Email (STRING --> CHAR254)
l_strustemail = IF_EMAIL.
IF l_strustemail <> if_email.
RAISE EXCEPTION TYPE cx_smime_crypto
EXPORTING
textid = cx_smime_crypto=>email_address_too_long
email = if_email.
ENDIF.
" Lookup in address book (no structural checks by this method)
CALL FUNCTION 'STRUSTCAB_GET_CERTS_BY_EMAIL'
EXPORTING
if_email = l_strustemail
IMPORTING
et_certificates = lt_strustcertificates
EXCEPTIONS
not_found = 1
invalid_email = 2
OTHERS = 3.
CASE sy-subrc.
WHEN 0.
" FOUND -> RETURN
et_certificates = lt_strustcertificates.
RETURN.
" The exception "NOT_FOUND" results in an empty list, which later
" leads to a "no certificate found" in CERTIFICATE_SELECTION.
" Don't need that code duplicate.
WHEN OTHERS.
" Not found
" would proceed with LDAP
ENDCASE.
endmethod
Method 2 - get certificate from LDAP, Active Directory
if we use LDAP / ActiveDirectory we can basically store user certificates there and then we can get them. Let's assume the user certificate (we would find user by Email) is stored in LDAP in the parameter USERCERTIFICATE
we extend our method for certificate retrieval with following procedures:
first let's bind to LDAP Server
CALL FUNCTION 'LDAP_SYSTEMBIND'
EXPORTING
serverid = gc_ldap_id
wait_time = gc_wait_time
EXCEPTIONS
no_authoriz = 1
config_error = 2
nomore_conns = 3
ldap_failure = 4
not_alive = 5
other_error = 6
OTHERS = 7.
IF sy-subrc NE 0.
RAISE EXCEPTION TYPE cx_smime_crypto
EXPORTING
textid = cx_smime_crypto=>FREETEXT_MESSAGE
krn_msg = 'LDAP BIND error '
email = if_email.
ENDIF.
Read user data from LDAP
" generate search. IF_MAIL - incoming variable.
CONCATENATE '(&(mail=' IF_EMAIL '))' INTO l_ldap_search.
" perform ldapsearch
CALL FUNCTION 'LDAP_READ'
EXPORTING
scope = 2
filter = l_ldap_search
IMPORTING
ldaprc = l_ldaprc
entries = l_entries
EXCEPTIONS
no_authoriz = 1
conn_outdate = 2
ldap_failure = 3
not_alive = 4
other_error = 5
others = 6.
if sy-subrc = 0.
* MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
* WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
endif.
unbind LDAP Server
CALL FUNCTION 'LDAP_UNBIND'
EXCEPTIONS
conn_outdate = 0
ldap_failure = 0
not_alive = 0
other_error = 0
OTHERS = 0.
IF sy-subrc NE 0.
* RAISE system_bind_error.
ENDIF.
retrieve certificate form l_entries
IF l_entries[] IS INITIAL.
concatenate 'EMPTY LDAP RESPONSE for email: ' if_email INTO error_msg.
RAISE EXCEPTION TYPE cx_smime_crypto
EXPORTING
textid = cx_smime_crypto=>FREETEXT_MESSAGE
krn_msg = error_msg
email = if_email.
endif.
read table l_entries into l_wa_entires index 1.
l_attributes = l_wa_entires-ATTRIBUTES.
read table l_attributes into l_wa_user_cert WITH TABLE KEY name = 'USERCERTIFICATE'.
l_tblx_user_cert = l_wa_user_cert-XVALS.
read table l_tblx_user_cert into l_linex_user_cert INDEX 1.
l_x_user_cert = l_linex_user_cert-VAL.
INSERT l_x_user_cert INTO TABLE et_certificates.
And that's it! Now we can encrypt our messages with user public certificates direct in SAP.