Friday, November 14, 2025

Analyzing TLS Negotiation With tshark

One of the ever strengthening domains of security posture is network cryptography.  Every few years a new protocol version, set of cipher suites or key exchanges are introduced to strengthen network cryptography.    The current network cryptography standard is TLSv1.3. Looking ahead, Quantum-safe key exchange algorithms are on the horizon with ML-KEM.  However, the maximum advertised cryptographic standards don't always represent what the client and server negotiation agree upon. For example, an older version of a client may may not support modern standards and request to connect with a weaker protocol like SSLv3 or weaker cryptographic cipher suites.  This begs the question, how can you gain visibility into the negotiated terms offered by the client and agreed upon or rejected by the server.

Wireshark and its command line equivalent tshark are packet analysis tools that we can use to watch the network traffic in real time to discern the cryptographic terms offered by the client and what was accepted by the server.

Let's look at a few examples with 
1. Oracle AI Database 26 (TCP port 2484)
2. Oracle Database 19c (TCP port 2484) 
3. Oracle Unified Directory (TCP port 1636).

tshark Command

In each of the examples, we will use the following tshark command with the exception of the port number.  For database queries, we will use port 2484. For Oracle Unified Directory, we will use port 1636.

$ sudo tshark -i any -d "tcp.port==2484,ssl" -V -a duration:10 2>&1 | egrep "^    TLSv|Handshake Protocol:|Cipher Suites \(|Cipher Suite:|^            Version: |Handshake Protocol: .* Hello|Record Layer|^                Supported Version:|^            Extension: key_share|^                Key Share extension|^                    Key Share Entry:|Extension: supported_groups|Supported Group:|Curve Type:|Named Curve:|Server Params"| uniq | sed -e "s/(0x.*)//g" -e "s/^.*Handshake Protocol: Client Hello/Client requested:/g" -e "s/.*Version:/   Protocol Version:/g" -e "s/.*Cipher Suites /   Cipher Suites Requested:/g" -e "s/.*Handshake Protocol: Server Hello/Server replied with:/g" |egrep -v "Server replied with: Done|Encrypted Handshake Message|Application Data Protocol: Application Data|Handshake Protocol: Certificate|Change Cipher Spec Protocol|http-over-tls" &


Oracle AI Database 26

Here is the command run against Oracle AI 26 database with port 2484 immediately after running the tshark command.

$ $ORACLE_HOME/bin/sqlplus system/Oracle123@pdb1_ssl

SQL*Plus: Release 23.26.0.0.0 - for Oracle Cloud and Engineered Systems on Thu Nov 13 20:49:49 2025
Version 23.26.0.0.0

Copyright (c) 1982, 2025, Oracle.  All rights reserved.

Last Successful login time: Thu Nov 13 2025 20:49:20 +00:00

Connected to:
Oracle AI Database 26ai Enterprise Edition Release 23.26.0.0.0 - for Oracle Cloud and Engineered Systems
Version 23.26.0.0.0

SQL> quit
Disconnected from Oracle AI Database 26ai Enterprise Edition Release 23.26.0.0.0 - for Oracle Cloud and Engineered Systems
Version 23.26.0.0.0


Here is the result returned by tshark for Oracle AI 26 database.  

Client requested:
Client requested:
   Protocol Version: TLS 1.2 
   Cipher Suites Requested:(10 suites)
                Cipher Suite: TLS_AES_256_GCM_SHA384 
                Cipher Suite: TLS_CHACHA20_POLY1305_SHA256 
                Cipher Suite: TLS_AES_128_CCM_SHA256 
                Cipher Suite: TLS_AES_128_GCM_SHA256 
                Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 
                Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 
                Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 
                Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 
                Cipher Suite: TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 
                Cipher Suite: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 
            Extension: supported_groups (len=56)
                    Supported Group: Unknown 
                    Supported Group: Unknown 
                    Supported Group: Unknown 
                    Supported Group: Unknown 
                    Supported Group: Unknown 
                    Supported Group: Unknown 
                    Supported Group: secp521r1 
                    Supported Group: secp384r1 
                    Supported Group: secp256r1 
                    Supported Group: x25519 
                    Supported Group: sect571r1 
                    Supported Group: sect571k1 
                    Supported Group: sect409r1 
                    Supported Group: sect409k1 
                    Supported Group: sect283r1 
                    Supported Group: sect283k1 
                    Supported Group: ffdhe8192 
                    Supported Group: ffdhe6144 
                    Supported Group: ffdhe4096 
                    Supported Group: ffdhe3072 
                    Supported Group: ffdhe2048 
                    Supported Group: sect233k1 
                    Supported Group: sect233r1 
                    Supported Group: secp224r1 
                    Supported Group: secp192r1 
                    Supported Group: sect163k1 
                    Supported Group: sect163r2 
   Protocol Version: TLS 1.3 
   Protocol Version: TLS 1.2 
            Extension: key_share (len=806)
                Key Share extension
                    Key Share Entry: Group: Unknown (512), Key Exchange length: 800
Server replied with:
Server replied with:
   Protocol Version: TLS 1.2 
            Cipher Suite: TLS_AES_256_GCM_SHA384 
   Protocol Version: TLS 1.3 
            Extension: key_share (len=772)
                Key Share extension
                    Key Share Entry: Group: Unknown (512), Key Exchange length: 768
Client requested:
Client requested:
   Protocol Version: TLS 1.2 
   Cipher Suites Requested:(10 suites)
                Cipher Suite: TLS_AES_256_GCM_SHA384 
                Cipher Suite: TLS_CHACHA20_POLY1305_SHA256 
                Cipher Suite: TLS_AES_128_CCM_SHA256 
                Cipher Suite: TLS_AES_128_GCM_SHA256 
                Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 
                Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 
                Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 
                Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 
                Cipher Suite: TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 
                Cipher Suite: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 
            Extension: supported_groups (len=56)
                    Supported Group: Unknown 
                    Supported Group: Unknown 
                    Supported Group: Unknown 
                    Supported Group: Unknown 
                    Supported Group: Unknown 
                    Supported Group: Unknown 
                    Supported Group: secp521r1 
                    Supported Group: secp384r1 
                    Supported Group: secp256r1 
                    Supported Group: x25519 
                    Supported Group: sect571r1 
                    Supported Group: sect571k1 
                    Supported Group: sect409r1 
                    Supported Group: sect409k1 
                    Supported Group: sect283r1 
                    Supported Group: sect283k1 
                    Supported Group: ffdhe8192 
                    Supported Group: ffdhe6144 
                    Supported Group: ffdhe4096 
                    Supported Group: ffdhe3072 
                    Supported Group: ffdhe2048 
                    Supported Group: sect233k1 
                    Supported Group: sect233r1 
                    Supported Group: secp224r1 
                    Supported Group: secp192r1 
                    Supported Group: sect163k1 
                    Supported Group: sect163r2 
   Protocol Version: TLS 1.3 
   Protocol Version: TLS 1.2 
            Extension: key_share (len=806)
                Key Share extension
                    Key Share Entry: Group: Unknown (512), Key Exchange length: 800
Server replied with:
Server replied with:
   Protocol Version: TLS 1.2 
            Cipher Suite: TLS_AES_256_GCM_SHA384 
   Protocol Version: TLS 1.3 
            Extension: key_share (len=772)
                Key Share extension
                    Key Share Entry: Group: Unknown (512), Key Exchange length: 768

The things to note from this output is that the client requested to connect with TLS 1.3 with the TLS_AES_256_GCM_SHA384 cipher suite using an unknown 768 bit key exchange group.  The key group is actually a hybrid TLS 1.3 connection using quantum-safe ML-KEM algorithm.  This algorithm is so new that RedHat/Oracle Linux 9 does not yet have it identified and thus marks it as Unknown.  To learn more about Oracle AI 26 database support of the new quantum-safe ML-KEM algorithm, go to the "Securing Oracle AI Database 26ai for the Quantum Era" blog.  The new ML-KEM algorithm groups are identified by IANA (https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8) as:
  • MLKEM512
  • MLKEM768
  • MLKEM1024
  • SecP256r1MLKEM768
  • X25519MLKEM768
  • SecP384r1MLKEM1024
Once RedHat/Oracle 9 and Wireshark get updated to support these groups, they will be accurately represented in the tshark output.

Oracle Database 19c

Here's the SQL*Plus command that we run for Oracle 19c database with port 2484 immediately after running the tshark command:

$ $ORACLE_HOME/bin/sqlplus system/Oracle123@pdb1_ssl

SQL*Plus: Release 19.0.0.0.0 - Production on Thu Nov 13 17:44:02 2025
Version 19.25.0.0.0

Copyright (c) 1982, 2024, Oracle.  All rights reserved.

Last Successful login time: Thu Nov 13 2025 17:29:44 +00:00

Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.25.0.0.0

SQL> quit;
Disconnected from Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.25.0.0.0


Here is the result returned by tshark for Oracle 19c database:

Client requested:
Client requested:
   Protocol Version: TLS 1.2 
   Cipher Suites Requested:(25 suites)
                Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 
                Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 
                Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA 
                Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 
                Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 
                Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA 
                Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 
                Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 
                Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 
                Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 
                Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 
                Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 
                Cipher Suite: TLS_RSA_WITH_AES_256_GCM_SHA384 
                Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA256 
                Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA 
                Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256 
                Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA256 
                Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA 
                Cipher Suite: TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 
                Cipher Suite: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 
                Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 
                Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 
                Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA 
                Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA 
                Cipher Suite: TLS_EMPTY_RENEGOTIATION_INFO_SCSV 
            Extension: supported_groups (len=32)
                    Supported Group: secp256r1 
                    Supported Group: secp521r1 
                    Supported Group: sect571k1 
                    Supported Group: sect571r1 
                    Supported Group: secp384r1 
                    Supported Group: sect409k1 
                    Supported Group: sect409r1 
                    Supported Group: sect283k1 
                    Supported Group: sect283r1 
                    Supported Group: secp224r1 
                    Supported Group: sect233k1 
                    Supported Group: sect233r1 
                    Supported Group: secp192r1 
                    Supported Group: sect163k1 
                    Supported Group: sect163r2
Server replied with:
Server replied with:
   Protocol Version: TLS 1.2 
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 
    TLSv1.2 Record Layer: Handshake Protocol: Server Key Exchange
        Handshake Protocol: Server Key Exchange
            EC Diffie-Hellman Server Params
                Curve Type: named_curve 
                Named Curve: secp256r1 
    TLSv1.2 Record Layer: Handshake Protocol: Client Key Exchange
        Handshake Protocol: Client Key Exchange

The things to note from the 19c connection output is that the client requested to connect with TLS 1.2 with the TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 cipher suite using an Elliptic Curve Diffe-Hellman key exchange. 

Oracle Unified Directory 14c

Here's the LDAP search command that we run for OUD immediately after running the tshark command with port 1636:

$ /u01/mw_oud14c/oud1/OUD/bin/ldapsearch -h poc.example.com -Z -X -p 1636 -D 'cn=Directory Manager' -j /u01/cfg/...pw -b dc=example,dc=com -s sub uid=user1 dn
dn: uid=user1,ou=People,dc=example,dc=com

 Here is the result returned by tshark for OUD directory server:

Client requested:
Client requested:
   Protocol Version: TLS 1.2 
   Cipher Suites Requested:(36 suites)
                Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 
                Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 
                Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 
                Cipher Suite: TLS_AES_128_GCM_SHA256 
                Cipher Suite: TLS_AES_256_GCM_SHA384 
                Cipher Suite: TLS_CHACHA20_POLY1305_SHA256 
                Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 
                Cipher Suite: TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 
                Cipher Suite: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 
               Cipher Suite: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 
                Cipher Suite: TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 
                Cipher Suite: TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 
                Cipher Suite: TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 
                Cipher Suite: TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 
                Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 
                Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 
                Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256 
                Cipher Suite: TLS_RSA_WITH_AES_256_GCM_SHA384 
                Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 
                Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 
                Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 
                Cipher Suite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 
                Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 
                Cipher Suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 
                Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA 
                Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 
                Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA 
                Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 
                Cipher Suite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA 
                Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA 
                Cipher Suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA 
                Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA 
                Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA256 
                Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA256 
                Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA 
                Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA 
            Extension: supported_groups (len=22)
                    Supported Group: x25519 
                    Supported Group: secp256r1 
                    Supported Group: secp384r1 
                    Supported Group: secp521r1 
                    Supported Group: x448 
                    Supported Group: ffdhe2048 
                    Supported Group: ffdhe3072 
                    Supported Group: ffdhe4096 
                    Supported Group: ffdhe6144 
                    Supported Group: ffdhe8192 
   Protocol Version: TLS 1.3 
   Protocol Version: TLS 1.2 
            Extension: key_share (len=107)
                Key Share extension
                    Key Share Entry: Group: x25519, Key Exchange length: 32
                    Key Share Entry: Group: secp256r1, Key Exchange length: 65
Server replied with:
Server replied with:
   Protocol Version: TLS 1.2 
            Cipher Suite: TLS_AES_128_GCM_SHA256 
   Protocol Version: TLS 1.3 
            Extension: key_share (len=36)
                Key Share extension
                    Key Share Entry: Group: x25519, Key Exchange length: 32

From the above output, we see that the LDAP search connected with TLS protocol version 1.3 using TLS_AES_128_GCM_SHA256  cipher suite with Elliptic Curve Diffie Hellman key exchange (x25519).

In all of the tshark examples provided, I presumed that both wireshark/tshark and sudo are available available for use on the database or directory server host.  If that is not the case you can work with your administrator to collect the tcpdump file, copy the file to another host and then run the tshark analaysis on that file.

$ sudo timeout 10 tcpdump -s 65535 -w /var/opt/tfile -i any "tcp port 1636 or tcp port 2484"

Copy the file (/var/opt/tfile or whatever name and location you used) to the host where tshark can analyize the tcpdump file.  Here is the tshark command using the tcpdump file as the input.  It is the same command as before but with an additional parameter to read the data from an input file.

$ sudo tshark -r /var/opt/tfile -i any -d "tcp.port==2484,ssl" -V -a duration:10 2>&1 | egrep "^    TLSv|Handshake Protocol:|Cipher Suites \(|Cipher Suite:|^            Version: |Handshake Protocol: .* Hello|Record Layer|^                Supported Version:|^            Extension: key_share|^                Key Share extension|^                    Key Share Entry:|Extension: supported_groups|Supported Group:|Curve Type:|Named Curve:|Server Params"| uniq | sed -e "s/(0x.*)//g" -e "s/^.*Handshake Protocol: Client Hello/Client requested:/g" -e "s/.*Version:/   Protocol Version:/g" -e "s/.*Cipher Suites /   Cipher Suites Requested:/g" -e "s/.*Handshake Protocol: Server Hello/Server replied with:/g" |egrep -v "Server replied with: Done|Encrypted Handshake Message|Application Data Protocol: Application Data|Handshake Protocol: Certificate|Change Cipher Spec Protocol|http-over-tls" 

Although Wiresharek and tshark are great external tools for analyzing the cryptographic negotiation at the network layer, my hope and desire for all network products is that they will one day log the agreed upon terms of cryptographic negotiation.  This will greatly streamline network cryptographic analysis and help IT professionals identify clients using weak cryptography that need to be updated to use modern cryptography and mischievous clients that are intentionally using weak cryptography to find weak points of entry for penetration and lateral movement once inside an organization.

Several yeas ago, OUD implemented a feature for this very purpose. It can be implemented on access and admin log publishers by setting log-connection-details:true.  For example:

set-log-publisher-prop --publisher-name "File-Based Access Logger" --set log-connection-details:true

Once enabled, secure connections log the protocol, version and cipher suite. For example:

[14/Nov/2025:17:14:29 +0000] CONNECT CONN_DETAILS conn=2 tlsVersion=TLSv1.3 cipherSuite=TLS_AES_128_GCM_SHA256

Log analytics tools such as OCI Logging Analytics can consume the log data and identify clients using weak cryptography as seen in the following dashboard example.  The upper right widget reveals clients using weak cryptographic protocols such as SSLv3, TLSv1.0, ... etc.   The widget right below it shows use of weak cryptographic cipher suites.


Details on OUD Logging Analytics is available on my blog here.

I hope you found this information informative and helpful.

Blessings!

Wednesday, November 12, 2025

Rotate Oracle Database CA-signed TLS Certificates

Transport Layer Security (TLS) certificate rotation is an annual part of database operationalization.  The purpose of this blog post is to know when and how to rotate certificate authority (CA) signed TLS certificate(s).

When To Rotate TLS Certificates

In short, the TLS certificate should be rotated before the certificate expires.  However, you have a range of operational approaches available.

1. SCHEDULE - Use your internal systems to track when each certificate should be rotated and schedule rotation at least a week in advance of certificate expiration.

2. SCAN - Proactively periodic review of each database host's certificate.  Here is a command that you can use on a Linux host to check the validity of a database server's certificate. 

timeout 3 openssl s_client -connect <database_host>:2484 2>&1 | openssl x509 -noout -text|egrep "^Certificate:|^        Issuer:|^        Subject|^        Validity|^            Not "
Certificate:
        Issuer: C = US, ST = Arizona, L = Scottsdale, O = "Starfield Technologies, Inc.", OU = http://certs.starfieldtech.com/repository/, CN = Starfield Secure Certificate Authority - G2
        Validity
            Not Before: Oct 27 17:49:47 2024 GMT
            Not After : Nov  6 16:19:28 2025 GMT
        Subject: CN = hrdb.dbauthdemo.com
        Subject Public Key Info:


3. SUPPORT CLIENT REACTION - Reactively respond to rejected secure client SQL connections with error "ORA-29024: Certificate validation failure". This happens when the certificate has expired but the database server has not yet been restarted.


4. SUPPORT SERVER REACTION - Reactively respond to an error logged by the database server after restarting with an expired certificate or see errors in the listener log ($ORACLE_BASE/diag/tnslsnr/hrdb/listener/trace/listener.log):  

13-NOV-2025 00:20:39 * 28791
ORA-28791: certificate verification failure
 TNS-12560: TNS:protocol adapter error
  TNS-00540: SSL protocol adapter failure

Or, secure client connections may be rejected with error  "ORA-28864: SSL connection closed gracefully" or "ORA-28860: Fatal SSL error".  These are errors that you may see after restarting a database with an expired certificate. You can use the Linux openssl command to determine if there is a valid certificate.  If "no peer certificate available" is returned, that means that the database server didn't load the certificate because it has expired.

timeout 3 openssl s_client -connect $(hostname -f):2484 -showcerts 
CONNECTED(00000003)
140280481429312:error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:ssl/record/rec_layer_s3.c:1544:SSL alert number 40
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 339 bytes
Verification: OK
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---


How To Rotate TLS Certificates

When it is time to rotate in the new certificate, here is the process for a certificate that is signed by a certificate authority.

1. Backup all of the existing wallets

cd $WALLET_ROOT
zip -r wallet-backup-$(date +'%Y%m%d').zip tls [0-9A-Z]*/tls


2. Download and extract the updated certificate from the certificate authority.  In my case, the downloaded zip file contains the current signed certificate (ee406cc00e4cb32a) in crt and pem formats and the certificate chain (sf_bundle-g2) in crt format.

unzip hrdb.dbauthdemo.com.zip
Archive:  hrdb.dbauthdemo.com.zip
  inflating: sf_bundle-g2.crt
  inflating: ee406cc00e4cb32a.crt
  inflating: ee406cc00e4cb32a.pem


3. Replace the certificate and certificate chain in each of the TLS wallets.

orapki wallet replace -wallet $WALLET_ROOT/tls -pwd Oracle123 -user_cert -cert $WALLET_ROOT/a5b3357724f807a.crt

orapki wallet replace -wallet $WALLET_ROOT/31E8327905743479E0632100000A7958/tls -pwd Oracle123 -user_cert -cert $WALLET_ROOT/a5b3357724f807a.crt

... for each PDBGUID wallet


4. Restart the database

5. Confirm the certificate successfully loaded with Linux openssl command or sqlplus.

Test with Linux openssl command:

timeout 3 openssl s_client -connect <database_host>:2484 2>&1 | openssl x509 -noout -text|egrep "^Certificate:|^        Issuer:|^        Subject|^        Validity|^            Not "
Certificate:
        Issuer: C = US, ST = Arizona, L = Scottsdale, O = "Starfield Technologies, Inc.", OU = http://certs.starfieldtech.com/repository/, CN = Starfield Secure Certificate Authority - G2
        Validity
            Not Before: Oct 27 17:49:47 2025 GMT
            Not After : Nov  6 16:19:28 2026 GMT
        Subject: CN = hrdb.dbauthdemo.com
        Subject Public Key Info:

Test with SQL*Plus command:

sqlplus system/Oracle123@pdb1_ssl

SQL*Plus: Release 19.0.0.0.0 - Production on Thu Nov 13 00:03:32 2025
Version 19.25.0.0.0

Copyright (c) 1982, 2024, Oracle.  All rights reserved.

Last Successful login time: Thu Nov 13 2025 00:02:55 +00:00

Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.25.0.0.0

SQL> 


6. Remove certs and certificate chain files

rm -f sf_bundle-g2.crt ee406cc00e4cb32a.crt ee406cc00e4cb32a.pem


That's it. I hope you found this information informative and helpful.

Blessings!

Friday, October 3, 2025

Constraining TNS Searches

This week, I had a most interesting customer request regarding limiting the scope of Oracle database name resolution (e.g. Transparent Network Substrate (TNS) / Net Service record lookups) search results by database clients to a single result.  The customer wanted the Oracle Unified Directory (OUD) directory service to limit the results returned by wild card searches by database clients to a single result.  For example, they didn't want a database client to be able to return all registered databases in OUD.

Fortunately with OUD this is a very easy problem to solve.  You simply change the system wide default size-limit to 1.  This will prevent anonymous and any non-administrative users from returning the full list of registered databases. However, it is important to note this is not a recommended approach for general use because most directory service client applications return more than one result.  In the case of TNS name resolution, that is the the only use case for normal clients.

With the default TNS configuration an anonymous search can list all registered databases:

$ ldapsearch -T -h tns1.example.com -p 1389 -b dc=example,dc=com -s sub 'orclNetDescString=*'  dn
dn: cn=mydb1,ou=Databases,cn=OracleContext,DC=example,DC=com

dn: cn=mypdb1_tns1,ou=Databases,cn=OracleContext,DC=example,DC=com

dn: cn=mytestdb,cn=OracleContext,DC=example,DC=com

Changing the system wide size-limit to 1 per OUD directory service instance limits the results returned to just 1 entry.

$ dsconfig -h tns1.example.com -X -p 4444 -D 'cn=Directory Manager' -j /u01/cfg/...pw --no-prompt set-global-configuration-prop --set size-limit:1

With this system wide change applied, here is what is now returned to the database client for a wildcard search attempting to show all databases:

$ ldapsearch -T -h tns1.example.com -p 1389 -b dc=example,dc=com -s sub 'orclNetDescString=*'  dn
dn: cn=mydb1,ou=Databases,cn=OracleContext,DC=example,DC=com

SEARCH operation failed
Result Code:  4 (Size Limit Exceeded)
Additional Information:  This search operation has sent the maximum of 1 entries to the client

Specific searches for an individual database continue to work as expected. For example:

$ ldapsearch -T -h tns1.example.com -p 1389 -b dc=example,dc=com -s sub 'cn=mydb1' orclNetDescString
dn: cn=mydb1,ou=Databases,cn=OracleContext,DC=example,DC=com
orclNetDescString: (DESCRIPTION= (ADDRESS = (PROTOCOL = TCP)(HOST = tns1.example.com )(PORT = 1521))(CONNECT_DATA = (SERVICE_NAME = mydb1 )))

Some directory experts might point out that this can be worked around by reducing the page size to 1. Again with OUD, that is a privilege that can be taken away and is not enabled by default for anonymous users as you can see from the example below:

ldapsearch -T -h tns1.example.com -p 1389 --simplePageSize 1 -b dc=example,dc=com -s sub 'orclNetDescString=*'  dn
SEARCH operation failed
Result Code:  50 (Insufficient Access Rights)
Additional Information:  The request control with Object Identifier (OID) "1.2.840.113556.1.4.319" cannot be used due to insufficient access rights


There is one thing that needs to be addressed.  TNS administrators are impacted by this system wide change as well. To resolve this constraint, we simply override the system wide size-limit with a user specific size-limit.  For example:

$ ldapmodify -h tns1.example.com -Z -X -p 1636 -D "cn=Directory Manager" -j /u01/cfg/...pw <<EOF
dn: cn=tnsadmin,ou=TNSAdmins,cn=OracleContext
changetype: modify
add: ds-rlim-size-limit
ds-rlim-size-limit: 0
EOF

Now, the TNS administrator has sufficient privilege to list all databases in OUD.

I hope you found this information useful and insightful.

Blessings!
























Tuesday, September 30, 2025

Entra ID RAS Integration

Real Application Security (RAS) provides fine grain access controls within the Oracle database for application users.  This capability can be extended to centralized database architectures such as Centrally Managed Users (CMU) and Entra ID integration.  Thomas Minne recently wrote up an excellent article titled "Unifying Identity and Data Security: Real Application Security with Active Directory" that illustrates how to configure RAS access controls of CMU roles by way of specifying the CMU database group with principal_name and the RAS xs_acl.ptype_db principal_type.

With CMU, database roles can be mapped as identified globally to Active Directory (AD) groups using the group's distinguished name (DN) in AD.  In the following example, we map the database roles idp_dba and to dbsession to AD groups  "cn=idp_dba,cn=Groups,dc=myco,dc=com" and "cn=dbsession,cn=Groups,dc=myco,dc=com" respectively:

DB Role For DBAs:
SQL> CREATE ROLE idp_dba IDENTIFIED GLOBALLY AS 'cn=idp_dba,cn=Groups,dc=myco,dc=com';
SQL> GRANT pdb_dba TO idp_dba;

DB Role For Users:
SQL> CREATE ROLE dbsession IDENTIFIED GLOBALLY AS 'cn=dbsession,cn=Groups,dc=myco,dc=com';
SQL> GRANT CREATE SESSION TO dbsession;

With Entra ID integration, the database roles are mapped to Entra ID app roles that are linked within Entra ID to Entra ID groups.  In the following example, we map the database roles idp_dba and dbsession to Entra ID app roles dba.role and session.role respectively:

DB Role For DBAs:
SQL> CREATE ROLE idp_dba IDENTIFIED GLOBALLY AS 'AZURE_ROLE=dba.role';
SQL> GRANT pdb_dba TO idp_dba;

DB Role For Users:
SQL> CREATE ROLE dbsession IDENTIFIED GLOBALLY AS 'AZURE_ROLE=session.role';
SQL> GRANT CREATE SESSION TO dbsession;

In both cases, the RAS access policy declarations can be applied to the CMU or Entra ID database role names.  For example, the dbsession can be granted minimal RAS select privilege and the idp_dba role can be granted maximum select privilege.  Here are examples borrowing from Thomas Minne's blog post:

    aces(1) := xs$ace_type(privilege_list => xs$name_list
                            ('select'),
                             principal_name => 'dbsession',
                             principal_type => xs_acl.ptype_db);

    aces(2) := xs$ace_type(privilege_list => xs$name_list
                            ('select','view_employee_details'),
                             principal_name => 'idp_dba',
                             principal_type => xs_acl.ptype_db);

A user that is a member of the dbsession group would only be able to return the limited results governed by the RAS rules for that access control. And a user that is a member of the idp_dba group would be able to see all the data within the contraints of rules of the RAS access controls for the idp_daba role.

I hope you find this educational and informative.

Blessings!

Monday, September 29, 2025

Creating Entra ID Enabled Net Service TNS Entries

Oracle Net Services provides name service resolution for Oracle database clients when looking up the connect string for a target database.  Cloud native Entra ID integration for Oracle database users is a new capability that provides centralized multi-factor authentication to end users and service accounts.

As customers explore transitioning their LDAP-based name service database entries to Entra ID integration (a.k.a. MSIE), one method is to duplicate all database entries with new entries that are tagged with _MSIE and incorporate the requisite TLS encrypted connectivity and Entra ID properties such as authentication method (e.g. interactive, passthrough, or service account), Entra ID tenant ID, Entra ID web app client ID and Entra ID web app database server URI.

A new manage_tns tool has been introduced to simplify creating and loading the Entra ID entries into the existing LDAP-based directory naming service.  Here is how to use manage_tns to duplicate all existing entries with new entries that include the _MSIE tag and include the Entra ID properties.

Step 1: Install python3-ldap and the manage_tns tool on to a Linux host

$ sudo install python3-ldap
$ cd /u01
$ curl -so manage_tns.sh https://raw.githubusercontent.com/oudlabs/manage_tns/refs/heads/main/manage_tns.sh
$ chmod 0700 manage_tns.sh


Step 2: Backup the primary naming context

$ /u01/manage_tns.sh export -h <dshost> -p <ldaps_port> -f tnsnames.ora --suffix "DC=example,DC=com"

Sample output:

Directory Server: ldaps://tns1.example.com:1636
User: Loging into directory service anonymously
Exporting pdb3...done
Export to tnsnames-msie.ora complete
$ cat tnsnames-msie.ora
pdb3=
   (DESCRIPTION=
         (ADDRESS=(PROTOCOL=TCPS)(HOST=pdb3.example.com)(PORT=2484))
      (CONNECT_DATA=
         (SERVER=DEDICATED)
         (SERVICE_NAME=pdb3.example.com)))


Step 3: Export the database entries from the naming context with MSIE data

$ /u01/manage_tns.sh exportmsie -h <dshost> -p <ldaps_port> -f tnsnames-msie.ora --suffix "DC=example,DC=com" --dbport 2484 --method interactive --tenantid 7f4c6e3e-a1e0-43fe-14c5-c2f051a0a3a1 --clientid e5124a85-ac3e-14a4-f2ca-1ad635cf781a --serveruri "https://dbauthdemo.com/16736175-ca41-8f33-af0d-4616ade17621"

Directory Server: ldaps://tns1.example.com:1636

Sample output:

Directory Server: ldaps://tns1.example.com:1636
User: Loging into directory service anonymously
Exporting pdb3...done
Export to tnsnames-msie.ora complete
$ cat tnsnames-msie.ora
PDB3_MSIE=
   (DESCRIPTION=
         (ADDRESS=(PROTOCOL=TCPS)(HOST=pdb3.example.com)(PORT=2484))
         (SECURITY=
            (SSL_SERVER_DN_MATCH=TRUE)
            (WALLET_LOCATION=SYSTEM)
            (TOKEN_AUTH=AZURE_INTERACTIVE)
            (TENANT_ID=7f4c6e3e-a1e0-43fe-14c5-c2f051a0a3a1)
            (CLIENT_ID=e5124a85-ac3e-14a4-f2ca-1ad635cf781a)
            (AZURE_DB_APP_ID_URI=https://dbauthdemo.com/16736175-ca41-8f33-af0d-4616ade17621))
      (CONNECT_DATA=
         (SERVER=DEDICATED)
         (SERVICE_NAME=pdb3.example.com)))


Step 4: Update the database server URI for every database in tnsnames-msie.ora

PDB3_MSIE=
   (DESCRIPTION=
         (ADDRESS=(PROTOCOL=TCPS)(HOST=pdb3.example.com)(PORT=2484))
         (SECURITY=
            (SSL_SERVER_DN_MATCH=TRUE)
            (WALLET_LOCATION=SYSTEM)
            (TOKEN_AUTH=AZURE_INTERACTIVE)
            (TENANT_ID=7f4c6e3e-a1e0-43fe-14c5-c2f051a0a3a1)
            (CLIENT_ID=e5124a85-ac3e-14a4-f2ca-1ad635cf781a)
            (AZURE_DB_APP_ID_URI=https://dbauthdemo.com/16781793-df98-94e1-2c51-8a91e8878171 ))
      (CONNECT_DATA=
         (SERVER=DEDICATED)
         (SERVICE_NAME=pdb3.example.com)))


Step 5: Load the MSIE tagged entries

$ /u01/manage_tns.sh load -h <dshost> -p <ldaps_port> --suffix "DC=example,DC=com" -f tnsnames-msie.ora


Step 6: Confirm that Oracle database clients can authenticate with Entra ID integration into each of the databases

See the following blog posts on how to setup the respective Oracle database clients:

I hope you found this information helpful and insightful.

Blessings!





How To Consolidate Oracle Naming Contexts

Oracle Net Services provides name service resolution for Oracle database clients when looking up the connect string for a target database.  Customers that have used Net Services for a long time may have accumulated a large number of Oracle contexts (a.k.a. directory service base suffixes) over time. Some customers have expressed an interest in consolidating all of the databases into a single naming context. For example, consider a customer that has databases in the following naming contexts:
  • DC=myco,DC=com
  • DC=corp,DC=myco,DC=com
  • DC=dev,DC=myco,DC=com
  • DC=acquiredco,DC=com
The customer would like to consolidate all of these naming contexts into a unified naming context of "DC=myco,DC=com" for all database entries.  In the past, this could be accomplished through a variety of means but all were fraught with a certain degree of risk and complications.  However, there is a new manage_tns tool available that handles this use case quite effortlessly.  Here is how to accomplish this objective in seven steps with manage_tns:

Step 1: Install python3-ldap and the manage_tns tool on to a Linux host

$ sudo install python3-ldap
$ cd /u01
$ curl -so manage_tns.sh https://raw.githubusercontent.com/oudlabs/manage_tns/refs/heads/main/manage_tns.sh
$ chmod 0700 manage_tns.sh

Step 2: Backup the primary naming context

$ /u01/manage_tns.sh export -h <dshost> -p <ldaps_port> -f tnsnames.ora --suffix "DC=myco,DC=com"

Step 3: Export the database entries from all other naming contexts

$ /u01/manage_tns.sh export -h <dshost> -p <ldaps_port> -f tnsnames-corp.ora --suffix "DC=corp,DC=myco,DC=com"

$ /u01/manage_tns.sh export
 -h <dshost> -p <ldaps_port>  -f tnsnames-dev.ora --suffix "DC=dev,DC=myco,DC=com"

$ /u01/manage_tns.sh export
 -h <dshost> -p <ldaps_port>  -f tnsnames-other.ora --suffix "DC=acquiredco,DC=com"

Step 4: Load the exported database entries into the primary naming context

$ /u01/manage_tns.sh load -h <dshost> -p <ldaps_port> -D <tns_admin_dn> -f tnsnames-corp.ora --suffix "DC=myco,DC=com"

$ /u01/manage_tns.sh load
 -h <dshost> -p <ldaps_port> -D <tns_admin_dn> -f tnsnames-dev.ora --suffix "DC=myco,DC=com"

$ /u01/manage_tns.sh load
 -h <dshost> -p <ldaps_port> -D <tns_admin_dn> -f tnsnames-other.ora --suffix "DC=myco,DC=com"

Step 5: Update client references to the new naming context in ldap.ora and JDBC connect lookups

Example of ldap.ora:

DEFAULT_ADMIN_CONTEXT = "DC=myco,DC=com"

Example of jdbc reference:

"jdbc:oracle:thin:@ldaps:<ds_host>:<ldaps_port>/<db_alias>,cn=OracleContext,DC=myco,DC=com"

Step 6: Obtain a list of all of the database entries from the legacy naming context

$ /u01/manage_tns.sh list -h <dshost> -p <ldaps_port> --suffix "DC=acquiredco,DC=com"


Step 7: Un-register database entries from the old contexts once you are certain that clients are no long referencing the old contexts

$ /u01/manage_tns.sh unregister -n <db_alias> -h <dshost> -p <ldaps_port> -f tnsnames-corp.ora --suffix "DC=corp,DC=myco,DC=com"


I hope you found this information helpful and insightful.

Blessings!





Wednesday, September 24, 2025

Simplifying LDAP-based Oracle Name Service Record Management

As customer's Oracle database estate expands on premises and across all major clouds (Oracle OCI, Microsoft Azure, Amazon AWS, and Google Cloud), they often desire to centralize name service resolution into LDAP-based directory services in order to ensure accuracy of the connect strings used by client applications.  This is particularly important for use cases like database migrations or employing custom connect strings.  This further exponentiated by the adoption of Entra ID integration where additional TLS and Entra ID connect string properties are required.  In order to address this growing need, I wrote a simple script for managing name service records and published it to GitHub at https://github.com/oudlabs/manage_tns.  This blog post just summarizes the use cases that it covers.

Installation

To install, just download from GitHub to a linux host.

curl -so manage_tns.sh https://raw.githubusercontent.com/oudlabs/manage_tns/refs/heads/main/manage_tns.sh


Usage

To see usage, just run the script with help subcommand

manage_tns.sh help


Register Database

Use the "register" subcommand to register a database into the directory service.

manage_tns.sh.sh register -n <db_alias> [options]


Unregister Database

Use the "unregister" subcommand to remove a database entry from the directory service.

manage_tns.sh.sh unregister -n <db_alias> [options]


List Registered Databases

Use the "list" subcommand to list all registered database in the directory service.

manage_tns.sh.sh list [options]


Show Database Registration Details

Use the "show" subcommand to show the details of a specific database from the directory service.

manage_tns.sh.sh show -n <db_alias> [options]


Examples


Register a database with alias name mypdb to the directory service.

$ manage_tns.sh register -n pdb1 -h tns.example.com -p 10636 --dbhost cdb1.example.com --dbport 1521 --dbproto TCP --service pdb1
Directory Server: ldaps://tns.example.com:10636
User: Loging into directory as cn=eusadmin,ou=EUSAdmins,cn=oracleContext
Enter directory service TNS admin user's password: *********
Register database pdb1
Database registration completed successfully



Register a database that includes TLS encryption and Entra ID integration details into the directory service.

manage_tns.sh register -n pdb2 -h tns.example.com -p 10636 --dbhost cdb1.example.com --dbport 2484 --dbproto TCPS --service pdb2.example.com --method interactive --tenantid 7f4c6e3e-a1e0-43fe-14c5-c2f051a0a3a1 --clientid e5124a85-ac3e-14a4-f2ca-1ad635cf781a --serveruri "https://dbauthdemo.com/16736175-ca41-8f33-af0d-4616ade17621"
Directory Server: ldaps://tns.example.com:10636
User: Loging into directory as cn=eusadmin,ou=EUSAdmins,cn=oracleContext
Enter directory service TNS admin user's password: *********
Register database pdb2
Database registration completed successfully


Register a database with a custom connection string into the directory service.

manage_tns.sh register -n rac1 --dbhost rac1.example.com -c "(DESCRIPTION=(CONNECT_TIMEOUT=90)(RETRY_COUNT=50)(RETRY_DELAY=3)(TRANSPORT_CONNECT_TIMEOUT=3)(ADDRESS_LIST=(LOAD_BALANCE=on)(ADDRESS=(PROTOCOL=TCP)(HOST=racnode1.example.com)(PORT=1521)))(ADDRESS_LIST=(LOAD_BALANCE=on)(ADDRESS=(PROTOCOL=TCP)(HOST=racnode2.example.com)(PORT=1521)))(ADDRESS_LIST=(LOAD_BALANCE=on)(ADDRESS=(PROTOCOL=TCP)(HOST=racnode3.example.com)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=rac1)))"
Directory Server: ldaps://tns1.example.com:10636
User: Loging into directory as cn=eusadmin,ou=EUSAdmins,cn=oracleContext
Enter directory service TNS admin user's password: *********
Register database rac1
Database registration completed successfully


List all databases registered in the directory service.

$ manage_tns.sh list
Directory Server: ldaps://tns1.example.com:10636
User: Loging into directory service anonymously
List registered databases

cn=pdb1,cn=OracleContext,dc=example,dc=com
orclNetDescString: (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=cdb1.example.com)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=pdb1)))

cn=pdb2,cn=OracleContext,dc=example,dc=com
orclNetDescString: (DESCRIPTION=(ADDRESS=(PROTOCOL=TCPS)(HOST=cdb1.example.com)(PORT=2484))(SECURITY=(SSL_SERVER_DN_MATCH=TRUE)(WALLET_LOCATION=SYSTEM)(TOKEN_AUTH=AZURE_INTERACTIVE)(TENANT_ID=7f4c6e3e-a1e0-43fe-14c5-c2f051a0a3a1)(AZURE_DB_APP_ID_URI=https://dbauthdemo.com/16736175-ca41-8f33-af0d-4616ade17621)(CLIENT_ID=e5124a85-ac3e-14a4-f2ca-1ad635cf781a))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=pdb2)))

cn=rac1,cn=OracleContext,dc=example,dc=com
orclNetDescString: (DESCRIPTION=(CONNECT_TIMEOUT=90)(RETRY_COUNT=50)(RETRY_DELAY=3)(TRANSPORT_CONNECT_TIMEOUT=3)(ADDRESS_LIST=(LOAD_BALANCE=on)(ADDRESS=(PROTOCOL=TCP)(HOST=racnode1.example.com)(PORT=1521)))(ADDRESS_LIST=(LOAD_BALANCE=on)(ADDRESS=(PROTOCOL=TCP)(HOST=racnode2.example.com)(PORT=1521)))(ADDRESS_LIST=(LOAD_BALANCE=on)(ADDRESS=(PROTOCOL=TCP)(HOST=racnode3.example.com)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=rac1)))


Show the details of one of the registered databases.

$ manage_tns.sh show -n pdb1
Directory Server: ldaps://tns1.example.com:10636
User: Loging into directory service anonymously
Show database pdb1
dn: cn=pdb1,cn=OracleContext,dc=example,dc=com
cn: pdb1
objectClass: orclApplicationEntity
objectClass: orclDBServer
objectClass: orclService
objectClass: top
objectClass: orclDBServer_92
orclDBGlobalName: pdb1
orclNetDescName: 000:cn=DESCRIPTION_0
orclNetDescString: (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=cdb1.example.com)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=pdb1)))
orclOracleHome: /dbhome_1
orclServiceType: DB
orclSid: pdb1
orclSystemName: cdb1.example.com
orclVersion: 121000

Show the connect string of a database entry.

$ manage_tns.sh showcs -n pdb2
Directory Server: ldaps://tns1.example.com:10636
User: Loging into directory service anonymously
Show connect string of database pdb2
(DESCRIPTION=
         (ADDRESS=(PROTOCOL=TCPS)(HOST=cdb1.example.com)(PORT=2484))
         (SECURITY=
            (SSL_SERVER_DN_MATCH=TRUE)
            (WALLET_LOCATION=SYSTEM)
            (TOKEN_AUTH=AZURE_INTERACTIVE)
            (TENANT_ID=7f4c6e3e-a1e0-43fe-14c5-c2f051a0a3a1)
            (AZURE_DB_APP_ID_URI=https://dbauthdemo.com/16736175-ca41-8f33-af0d-4616ade17621)
            (CLIENT_ID=e5124a85-ac3e-14a4-f2ca-1ad635cf781a))
      (CONNECT_DATA=
         (SERVER=DEDICATED)
         (SERVICE_NAME=pdb2)))


Unregister a database entry from the directory service.

$ manage_tns.sh unregister -n pdb1
Directory Server: ldaps://tns1.example.com:10636
User: Loging into directory as cn=eusadmin,ou=EUSAdmins,cn=oracleContext
Enter directory service TNS admin user's password: *********
Unregister database pdb1
Database unregistration completed successfully


That concludes this blog post. 

I hope that you found it useful and informative.

Blessings!