UTL_HTTP, secure hosts and ORA-24263 certificate errors

Posted by

Security eh? It is just one of those little things that is good to have in a databaseSmile. The “problem” with security is that it often adds complexity to your environment, but I’d rather have a little extra complexity than have my personal details splattered all over the dark web in some database of the Australian population.

Now I know there’s perhaps a certain hypocrisy I can be accused of in stating this from a position of having a blog, a Youtube channel and open Twitter DMs, where just about any information about is readily available to all…but can we at least all agree that security is important Smile

A common security question that comes up on AskTom is related to UTL_HTTP (or any mechanism that reaches out from the database over the network). When I say “common question”, it is not the first question that comes up – that one is always about network ACLs. But once your ACLs are sorted out, the next security obstacle that typically arises is dealing with SSL and certificates.

Once we head into the realm of certificates and guaranteeing that a host/target is who it claims to be, UTL_HTTP is (quite rightly) very particular about initiating a communication with a remote host. For example, if you try to communicate securely with ‘www.oracle.com’ and and fire up ‘openssl’ to get the “true” name of this site you’ll find that this is not the name of the host in the certificate.

[oracle@db192 ~]$ openssl s_client -connect www.oracle.com:443
...
C = US, ST = California, L = Redwood City, O = Oracle Corporation, CN = www-cs-02.oracle.com

Thus when you are using UTL_HTTP (or UTL_SMTP etc) to communicate securely with www.oracle.com via a certificate that you have downloaded/imported into your wallet, we’re going to see “www-cs-02.oracle.com” in the certificate and respond with:

ERROR at line 1:
ORA-29273: HTTP request failed
ORA-06512: at "SYS.UTL_HTTP", line 1501
ORA-24263: Certificate of the remote server does not match the target address.
ORA-06512: at "SYS.UTL_HTTP", line 380
ORA-06512: at "SYS.UTL_HTTP", line 1441
ORA-06512: at line 1

Back in 12.2, we added a capability to handle this discrepancy between the public host name and the certificate host name via a new parameter for UTL_HTTP


SQL> DESC UTL_HTTP

...
...
FUNCTION BEGIN_REQUEST RETURNS REQ
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 URL                            VARCHAR2                IN
 METHOD                         VARCHAR2                IN     DEFAULT
 HTTP_VERSION                   VARCHAR2                IN     DEFAULT
 REQUEST_CONTEXT                BINARY_INTEGER          IN     DEFAULT
 HTTPS_HOST                     VARCHAR2                IN     DEFAULT
 
...
...

If you are only dealing a single target host, that is fine. You would use openssl to work out what name you want to pass for https_host and you’re done. But what if the hosts you are communicating with are many and/or dynamic. For example, you might be communicating with mail servers based on a users email domain. How can we (at runtime) automatically work out what the value for ‘https_host’ should be when initiating a conversation with UTL_HTTP?

External tables can come to the rescue here. We can take advantage of the preprocessor facilities to dynamically extract the host name using ‘openssl’.

I’ll put my hosts in a flat file, but they could be in any place where you can access them from your external table definition.

select host from my_table;

Let’s say that yields a file ‘host.dat’ like this:

[oracle@lin122 tmp]$ cat host.dat
www.oracle.com
www.outlook.com

Now I can use openssl and some parsing to extract the secure name that you want.

[oracle@lin122 tmp]$ cat ssl_check.sh
#/bin/bash
/usr/bin/cat $1 | while read HOST 
do
  /usr/bin/echo -n | /usr/bin/openssl s_client -connect $HOST:443 2>/dev/null | \
      /usr/bin/awk '/Certificate chain/ , /Server certificate/' | \
      /usr/bin/grep ' 0 s:' | /usr/bin/awk -v H=$HOST -F= '{print H","$NF}'
done

Then I can hook that up as an external table with a pre-processor.


create or replace directory tmp as '/tmp';

create table secure_host (
  name     varchar2(50),
  ssl_name varchar2(50)
)
organization external (
  type oracle_loader
  default directory tmp
  access parameters (
    records delimited by newline
    preprocessor tmp:'ssl_check.sh'
    fields terminated by ','
    missing field values are null
    (
      name     char(50),
      ssl_name char(50)
    )
  )
  LOCATION ('host.dat')
)
reject limit unlimited;

So this will

– read host.dat
– pass that file name to the script
– the script loops through and finds the secure host name
– sends host and secure host back, eg

SQL> select * from secure_host;

NAME                 SSL_NAME
-------------------- ------------------------------ 
www.oracle.com       www-cs-01.oracle.com
www.outlook.com      outlook.com

That gives you what you need to pass into UTL_HTTP and the like.

Got some thoughts? Leave a comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.