07.05.2014 Views

OpenSRS API Integration for XML

OpenSRS API Integration for XML

OpenSRS API Integration for XML

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

<strong>OpenSRS</strong> <strong>API</strong> <strong>Integration</strong> <strong>for</strong> <strong>XML</strong>


Table of Contents<br />

Introduction...............................................................................3<br />

Purpose..................................................................................3<br />

Audience................................................................................4<br />

Using HTTPS Post to Access <strong>OpenSRS</strong>............................................4<br />

Authenticating with the <strong>OpenSRS</strong> <strong>API</strong>.........................................4<br />

Testing environment................................................................4<br />

Connection In<strong>for</strong>mation............................................................5<br />

MD5 authentication...............................................................5<br />

Construction of the POST Data...................................................5<br />

Response Messages.................................................................6<br />

Troubleshooting HTTPS Post......................................................7<br />

<strong>OpenSRS</strong> protocol.......................................................................8<br />

Protocol message structure.......................................................9<br />

OPS message examples..........................................................13<br />

Semantic validity and <strong>API</strong> implementation.................................15<br />

Writing Your Own Client.............................................................17<br />

<strong>XML</strong> client protocol fundamentals.............................................17<br />

MD5 Examples.......................................................................18<br />

Coding Examples...................................................................20<br />

Perl example......................................................................20<br />

PHP example......................................................................24<br />

VB6 example......................................................................26<br />

VB .NET example................................................................31<br />

Java example.....................................................................32<br />

Data exchange......................................................................39<br />

Authentication handshake.......................................................39<br />

Encryption............................................................................42<br />

Reseller Agent Return Codes.......................................................43


Introduction<br />

Welcome to the <strong>OpenSRS</strong> <strong>API</strong> <strong>Integration</strong> guide <strong>for</strong> the registration and<br />

management of domain names and domain related services.<br />

Using this document, you can provide <strong>OpenSRS</strong> functionality to your<br />

customers by integrating <strong>API</strong> commands into your website that can send <strong>XML</strong><br />

requests to <strong>OpenSRS</strong> over HTTPS Post. You can also use <strong>API</strong> commands to<br />

run queries or automate tasks you would otherwise per<strong>for</strong>m manually using<br />

the <strong>OpenSRS</strong> Reseller Web Interface (RWI).<br />

You can leverage the <strong>API</strong> to allow registrants to view and update their<br />

contact details, nameservers, transfer auth codes, domain locking, whois<br />

privacy, and username and password settings. Additionally, the <strong>API</strong> can be<br />

used to per<strong>for</strong>m domain availability lookups, provide domain search<br />

suggestions and aftermarket domain lookups, as well as process<br />

registrations, transfers, and renewals.<br />

Registrants are set up with a profile in which multiple domains can be stored.<br />

A profile is defined by a username, password, and one of the domains in the<br />

profile. When requesting in<strong>for</strong>mation or updating domain in<strong>for</strong>mation, an<br />

authorization cookie needs to be requested first using a domain in the profile<br />

and the username and password <strong>for</strong> the profile. The cookie is then submitted<br />

with the request to look up or modify a domain's details, as well as when<br />

changing name servers assigned to a registered domain.<br />

Purpose<br />

The method of sending commands to <strong>OpenSRS</strong> using HTTPS Post supports<br />

communication between a client process and the <strong>OpenSRS</strong> system. This<br />

document describes how to <strong>for</strong>mulate the <strong>XML</strong> commands and how to use<br />

HTTPS Post to send the <strong>XML</strong> commands to <strong>OpenSRS</strong>.<br />

Using this document as a reference, you can use any programming language<br />

to write an implementation that supports this communication. If you are<br />

writing your own implementation, please refer to the "Design Considerations"<br />

section.<br />

The process <strong>for</strong> executing commands consists of <strong>for</strong>mulating the command in<br />

<strong>XML</strong> and sending it to <strong>OpenSRS</strong> via HTTPS Post. This guide outlines the basic<br />

method <strong>for</strong> creating the <strong>XML</strong> in a <strong>for</strong>mat usable by <strong>OpenSRS</strong> and includes<br />

some language-specific methods.<br />

The protocol assumes that the client process that is requesting an action<br />

waits <strong>for</strong> a result from the server process in response to the requested<br />

action. The protocol does not support session tracking.


Audience<br />

This document assumes that you are familiar with <strong>XML</strong> document design and<br />

the methods <strong>for</strong> sending data via HTTPS Post.<br />

Using HTTPS Post to Access <strong>OpenSRS</strong><br />

The <strong>OpenSRS</strong> server supports SSL encryption and handles <strong>XML</strong> posts from<br />

<strong>OpenSRS</strong> authorized Resellers. The <strong>OpenSRS</strong> server:<br />

Applies IP address authentication to all HTTPS Post requests.<br />

Authenticates the user by verifying the username and MD5 signature<br />

of the <strong>XML</strong>, signed using the Resellers private key (generated in the<br />

RWI) in the request header.<br />

<strong>OpenSRS</strong> uses <strong>XML</strong>, because it is a more structured and manageable<br />

approach than using Name Value Pairs.<br />

Authenticating with the <strong>OpenSRS</strong> <strong>API</strong><br />

To authenticate against the <strong>OpenSRS</strong> <strong>API</strong> service, you need your reseller<br />

username, and a private key that you can generate from the Reseller Web<br />

Interface. (In the Profile Management section, click Generate New Private<br />

Key).<br />

For the Live environment, the IP that connects to the <strong>API</strong> service must be<br />

added to an acceptance list. In the Profile Management section of the<br />

Reseller Web Interface, click Add IPs <strong>for</strong> Script/<strong>API</strong> Access and add the IP<br />

address to the list of allowed addresses.<br />

Testing environment<br />

<strong>OpenSRS</strong> provides a full test environment to assist with developing and<br />

testing <strong>API</strong> integration. The Horizon test environment duplicates the<br />

functionality of the Live environment, and is connected to the test<br />

environments of all the registry plat<strong>for</strong>ms.<br />

Transactions on Horizon are not real – in other words, if you register a<br />

domain using Horizon, it is registered on the test environment of the registry<br />

in question, but the domain does not resolve. Your Horizon account is funded<br />

with money to simulate payment <strong>for</strong> transactions you per<strong>for</strong>m. If you<br />

required additional testing funds, you can contact Reseller Support.<br />

The Test environment <strong>API</strong> also requires a private key, but unlike the Live<br />

environment, it doesn't require you to authorize your IP address.


Connection In<strong>for</strong>mation<br />

Live production environment<br />

Server: rr-n1-tor.opensrs.net/<br />

Port: 55443<br />

OT&E test environment<br />

Server: horizon.opensrs.net/<br />

Port: 55443<br />

MD5 authentication<br />

The MD5 Signature provides the authentication required by <strong>OpenSRS</strong>. The<br />

process involves two steps:<br />

1. Obtain an MD5 signature of the <strong>XML</strong> Content and the Private Key.<br />

Note: The <strong>XML</strong> and the Private Key are concatenated.<br />

2. Per<strong>for</strong>m another MD5 of the signature from Step 1 with the Private<br />

Key.<br />

Note: The MD5 Signature from Step 1 and the Private key are<br />

concatenated.<br />

See the section"Writing Your Own Client" <strong>for</strong> examples of adding an MD5<br />

Signature and creating the <strong>XML</strong> packet.<br />

Construction of the POST Data<br />

The header <strong>for</strong> the POST data should have the following <strong>for</strong>mat. The items in<br />

italics should be replaced by the user- and command-specific in<strong>for</strong>mation.<br />

POST / HTTP/1.0<br />

Content-Type: text/xml<br />

X-Username: <strong>OpenSRS</strong> Username<br />

X-Signature: MD5 Signature<br />

Content-Length: Length of <strong>XML</strong> Document<br />

Following this header should be one blank line followed by the <strong>XML</strong> document<br />

that contains the <strong>OpenSRS</strong> command data. The header combined with the<br />

<strong>XML</strong> makes up the packet that is sent to <strong>OpenSRS</strong> to execute your<br />

command. This packet is what is sent to the server and port listed above,<br />

depending on your environment, to execute the command.


For more in<strong>for</strong>mation regarding the transmission of data over HTTPS, refer to<br />

this document: http://www.ietf.org/rfc/rfc2616.txt<br />

Response Messages<br />

The process returns a response message to a client in answer to an action<br />

that was executed on its behalf. Responses contain data that is appropriate<br />

<strong>for</strong> the action that was executed. In some cases, this may be simple strings;<br />

in other cases, this may be lists of in<strong>for</strong>mation. This response is returned in<br />

the <strong>for</strong>m of an <strong>XML</strong> document.<br />

Common fields<br />

There are a few common fields that all responses share, regardless of the<br />

action to which they are responding. The following fields comprise a standard<br />

response message. Some actions only use standard response messages.<br />

Parameter<br />

name<br />

protocol<br />

action<br />

response_code<br />

response_text<br />

is_success<br />

Definition/Value<br />

The protocol that is being used (XCP).<br />

In the case of responses, this is always REPLY.<br />

Response code (meaning is action-specific).<br />

Response text (meaning is action-specific).<br />

Indicates whether the command was successful. Returns 0 if not<br />

successful and 1 if the action was successful.<br />

Optional fields<br />

In addition, the structure may contain the following fields, depending on the<br />

specific action that was requested.<br />

Parameter<br />

name<br />

attributes<br />

Definition/Value<br />

A hash that contains any specific parameters or attributes to be<br />

sent along with the action request.


Troubleshooting HTTPS Post<br />

Note: The client timeout value <strong>for</strong> <strong>OpenSRS</strong> <strong>API</strong> connections is 80 seconds.<br />

401 Authentication Error<br />

Check that you are using the correct Private Key <strong>for</strong> the right system –<br />

Horizon or Production.<br />

Check that you have the correct RSP username.<br />

Check that the IP address of the machine transmitting the data to the<br />

<strong>OpenSRS</strong> server is in your list of allowed IP addresses in the Reseller<br />

Web Interface.<br />

If the above checks are correct, the problem is with the MD5:<br />

• Ensure that you have concatenated the <strong>XML</strong> content and the Private<br />

Key.<br />

• Ensure that you have per<strong>for</strong>med an MD5 twice. See the MD5 section<br />

<strong>for</strong> more in<strong>for</strong>mation.<br />

• Ensure that your HTTP Post implementation is not adding any extra<br />

in<strong>for</strong>mation. Some implementations of HTTP Post add a NULL to the<br />

end of the HTTP Request. This is reflected in the MD5 and causes an<br />

authentication error.<br />

If you are still not connecting properly, check the result of the MD5<br />

Hash:<br />

<br />

<br />

Some MD5 algorithms put the MD5 hash in uppercase. Make sure that<br />

the result is in lowercase be<strong>for</strong>e sending it to <strong>OpenSRS</strong>.<br />

Some MD5 algorithms need to convert the string to bytes be<strong>for</strong>e<br />

generating the hash. Make sure this is done properly. You can test<br />

your script by per<strong>for</strong>ming an MD5 on the following text:<br />

Text:<br />

Connectto<strong>OpenSRS</strong>viaSSL<br />

MD5 Result:<br />

Invalid <strong>XML</strong> Response<br />

e787cc1d1951dfec4827cede7b1a0933<br />

Make sure you are sending the <strong>XML</strong>. The <strong>XML</strong> used in the MD5 is only <strong>for</strong><br />

authentication purposes. You must also send the <strong>XML</strong> as part of the content<br />

header.


<strong>OpenSRS</strong> protocol<br />

Purpose<br />

The purpose of the <strong>OpenSRS</strong> Protocol (OPS) is to support the passing of<br />

messages between processes in the <strong>OpenSRS</strong> Architecture.<br />

Design considerations<br />

The OPS uses <strong>XML</strong>-based messages. By using a meta language to describe<br />

the protocol, it can remain programming language-neutral.<br />

Any appropriate transport mechanism can be used to pass OPS protocol<br />

messages between processes, provided the message is reassembled<br />

precisely on the receiving end. Discussion of transport mechanisms is outside<br />

the scope of this document.<br />

Process flow<br />

When a process sends a message to another process, it generates an OPS<br />

protocol message that represents the data being sent. The OPS message is<br />

then passed to the other process, which can act on it as required and return<br />

any in<strong>for</strong>mation that is needed (again, as a protocol message).<br />

The generation of protocol messages is done with an <strong>API</strong> that is written <strong>for</strong><br />

the particular programming language being used (<strong>for</strong> example, Perl or C++).<br />

The <strong>API</strong> handles the details of encoding and decoding protocol messages<br />

from and to appropriate data structures <strong>for</strong> the language being used.


Protocol message structure<br />

DTD<br />

An OPS protocol message is an <strong>XML</strong> document, which satisfies the following<br />

Document Type Declaration (DTD).<br />

ops.dtd<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />


<br />

<br />

<br />

<br />

<br />

<br />

Description<br />

The preamble of an OPS message must contain encoding and DOCTYPE<br />

in<strong>for</strong>mation specifying the correct DTD (ops.dtd).<br />

<br />

<br />

The start and end of an OPS message 'envelope' are delimited by<br />

and tags.<br />

<br />

?<br />

?<br />

?<br />

<br />

A message consists of two basic parts: a header and a body. The header is<br />

delimited by and and contains in<strong>for</strong>mation that is<br />

related to protocol transport. Currently the OPS protocol version is<br />

supported. It is delimited by and tags.<br />

The body is delimited by and tags. Currently the body can<br />

only contain one component, which is the 'data_block'. The data block<br />

contains an <strong>XML</strong> representation of a data structure, which in turn contains<br />

the in<strong>for</strong>mation being passed by the process. The data block is delimited by<br />

and tags.


Example<br />

<br />

?<br />

?<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

The data structure within the data block is a represented according to data<br />

type. The following data types are supported:<br />

Data type<br />

associative<br />

array (hash)<br />

array<br />

array or<br />

associative<br />

array elements<br />

Definition/Value<br />

<br />

<br />

<br />

Where key is the name of the key used to access the element. For<br />

an array, it is an integer (0...N). For an associative array, it is a<br />

string.<br />

Example <strong>for</strong> assoc array:<br />

<br />

Tom<br />

Jones<br />

<br />

Example <strong>for</strong> array:<br />

<br />

example1.com<br />

example2.com<br />

<br />

The class attribute is optional. If specified, it refers to a class<br />

name that can be used to reconstruct the data into an object<br />

when decoded.


Data type<br />

Definition/Value<br />

The actual details of this are implementation specific. For<br />

example, <strong>for</strong> a Perl implementation the class name would be used<br />

to bless the underlying associative array (hash), back into an<br />

object.<br />

Example <strong>for</strong> class:<br />

<br />

<br />

<br />

Tom<br />

Jones<br />

<br />

<br />

<br />

scalars (<strong>for</strong><br />

example,<br />

strings,<br />

integers)<br />

<br />

scalar reference <br />

Data types can be arbitrarily nested. For example, you could have an array<br />

of an array of associative arrays. Any complex data type can be represented,<br />

provided the base data type is an array or an associative array.


OPS message examples<br />

Example 1<br />

This example shows an OPS message that encodes an associative array that<br />

contains an array of values:<br />

<br />

<br />

<br />

<br />

1.0<br />

<br />

<br />

<br />

<br />

<br />

<br />

ns1.example.com<br />

ns2.example.com<br />

ns3.example.com<br />

<br />

<br />

<br />

<br />

<br />

Example 2<br />

This example shows an OPS message that encodes an associative array that<br />

contains other associative arrays:<br />

<br />

<br />

<br />


1.0<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

Tom<br />

Jones<br />

<br />

<br />

<br />

<br />

Anne<br />

Smith<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

Example 3<br />

This example shows an OPS message that encodes a scalar value:<br />

<br />

<br />

<br />

<br />

1.0


<br />

<br />

Tom Jones<br />

<br />

<br />

<br />

Semantic validity and <strong>API</strong> implementation<br />

Any <strong>API</strong> implementation that encodes/decodes OPS messages should be<br />

reflexive. That means that, if a message is encoded and then decoded, the<br />

results of that decoding and the original message should be identical. In<br />

other words:<br />

MSG A := decode (encode (MSG A) )<br />

Alternatively,<br />

let MSG A' := encode (MSG A)<br />

then MSG A := decode (MSG A')<br />

This restriction can be relaxed when it comes to the ordering of array<br />

elements and associative array elements in the OPS message. As long as the<br />

semantic meaning of the elements is preserved (semantic equivalence), the<br />

actual textual ordering in the <strong>XML</strong> stream is not important.<br />

This is because the <strong>XML</strong> data structure representation uses element numbers<br />

(in the case of array) and field names (in the case of associative arrays) to<br />

represent the data stream, and this in<strong>for</strong>mation can be used by the <strong>API</strong> to<br />

reconstruct the <strong>XML</strong> representation back into an in-memory data structure.<br />

This approach supports languages in which the ordering of elements <strong>for</strong> inmemory<br />

data structures is not deterministic., <strong>for</strong> example, Perl hashes<br />

(associative arrays), where the physical ordering of elements within the hash<br />

is not guaranteed.


Example 1<br />

The following two data blocks are considered semantically the same. Notice<br />

that the order of elements is not the same, but the key values allow the data<br />

blocks to be decoded into the same memory structure (array).<br />

MSG A<br />

<br />

MSG B<br />

<br />

<br />

<br />

ns1.example.com<br />

ns2.example.com<br />

ns3.example.com<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

ns3.example.com<br />

ns2.example.com<br />

ns1.example.com<br />

<br />

<br />


Example 2<br />

The following two data blocks are considered semantically the same. Notice<br />

that the order of fields is not the same, but the key values allow the data<br />

blocks to be decoded into the same memory structure (associative array).<br />

MSG A<br />

<br />

MSG B<br />

<br />

Tom<br />

Jones<br />

<br />

<br />

<br />

<br />

Jones<br />

Tom<br />

<br />

<br />

Writing Your Own Client<br />

This section contains an explanation of the <strong>OpenSRS</strong> client/server data<br />

exchange. This in<strong>for</strong>mation is useful if you want to write your own client.<br />

<strong>XML</strong> client protocol fundamentals<br />

In our <strong>XML</strong> Client Protocol (XCP), the sender of a message (request or reply)<br />

must always precede the message with the header 'Content-Length: X',<br />

where 'X' is the number of bytes in the actual message (without the header).<br />

This header must be followed by a carriage return and line feed combination.<br />

Counted bytes only occur on the first non-blank line.


Example<br />

Content-length: 55\015\012<br />

# blank lines are ignored<br />

# carriage return/line feed<br />

<br />

<br />

<br />

<br />

0.9<br />

<br />

<br />

[ etc ]<br />

<br />

XCP allows empty space to be placed in the <strong>XML</strong> message, as long as the<br />

<strong>XML</strong> is still valid, so empty lines or end-of-line characters may be inserted<br />

(though they must be counted in the byte count).<br />

For more in<strong>for</strong>mation regarding the transmission of data over HTTPS, refer to<br />

this document: http://www.ietf.org/rfc/rfc2616.txt<br />

MD5 Examples<br />

The following examples show how to add an MD5 Signature and create an<br />

<strong>XML</strong> packet <strong>for</strong> the various client languages.<br />

PERL<br />

use Digest::MD5 qw/md5_hex/;<br />

md5_hex(md5_hex($xml, $private_key),$private_key)<br />

PHP<br />

md5(md5($xml.$private_key).$private_key);


VB6<br />

Using the “di_MD5DLL.dll” from DI Management<br />

This free cryptographic software code was written or adapted in Visual Basic<br />

and ANSI C by David Ireland.<br />

http://www.di-mgt.com.au/crypto.html#MD5<br />

Private Declare Function MakeMD5Digest Lib "di_MD5DLL.dll" _<br />

(ByVal sData As String, ByVal sDigest As String) As Long<br />

Public Function MD5Encode(ByVal sData As String) As String<br />

Dim iRet As Long<br />

Dim sDigest As String<br />

' Set sDigest to be 32 chars<br />

sDigest = String(32, " ")<br />

iRet = MakeMD5Digest(sData, sDigest)<br />

MD5Encode = Trim(sDigest)<br />

End Function<br />

MD5Encode(MD5Encode(p<strong>XML</strong>Doc.xml & strPrivateKey) & strPrivateKey)<br />

VB .NET<br />

Public Function cMD5(ByVal str As String) As String<br />

'Must have Imports System.Web.Security in General Declarations<br />

Dim Hash As String =<br />

FormsAuthentication.HashPasswordForStoringInConfigFile(str, "MD5")<br />

Return Hash.ToLower<br />

End Function<br />

cMD5(cMD5(str & PRIVATE_KEY) & PRIVATE_KEY))<br />

JAVA<br />

protected String md5Sum(String str) {<br />

String sum = new String();<br />

try {


MessageDigest md5 = MessageDigest.getInstance("MD5");<br />

sum = String.<strong>for</strong>mat("%032x", new BigInteger(1,<br />

md5.digest(str.getBytes())));<br />

}<br />

} catch (Exception ex) {<br />

}<br />

return sum;<br />

public String getSignature(String xml) {<br />

}<br />

return md5Sum(md5Sum(xml + privateKey) + privateKey);<br />

Coding Examples<br />

Perl example<br />

#!/usr/bin/perl<br />

use strict;<br />

use warnings;<br />

########################################################<br />

# Example script that takes registrant credentials in<br />

# from CGI variables and pulls all info about a domain.<br />

# A cookie is requested via a subroutine and is the<br />

# first of two calls to the <strong>API</strong>. The second is the query<br />

# <strong>for</strong> the domain's in<strong>for</strong>mation.<br />

########################################################<br />

## Reseller Configuration Variables<br />

my $rspusername = 'username'; # Your <strong>OpenSRS</strong> Reseller User Name<br />

my $private_key='privatekey'; # Your Private Key Generated In The RWI<br />

## Connection Location:<br />

my $REMOTE_HOST = "horizon.opensrs.net:55443";<br />

## CGI Variable Handling Definitions<br />

use vars qw(%in $cgi);


( %in, $cgi) = ();<br />

# Required Perl Modules<br />

use CGI ':cgi-lib'; # Optional To CGI Handling<br />

use HTTP::Request::Common;<br />

use Digest::MD5 qw/md5_hex/;<br />

use LWP::UserAgent;<br />

use Data::Dumper;<br />

use <strong>XML</strong>::Simple; # Can Be Replaced With Preferred <strong>XML</strong> Parser<br />

# NOTE: LWP requires that Crypt::SSLeay is also installed <strong>for</strong> an HTTPS<br />

call<br />

# Define Data And Connection Handlers And CGI Handling<br />

my $xmltohash = new <strong>XML</strong>::Simple; # Change To <strong>XML</strong> Parser Requires Update<br />

Here<br />

my $ua = LWP::UserAgent->new;<br />

# Get, Read, Parse Registrant Credentials From CGI Submitted Form<br />

$cgi = $ENV{SCRIPT_NAME};<br />

%in = ();<br />

ReadParse(\%in);<br />

my $domain = $in{domain}; # Registrant's Domain being queried<br />

my $username = $in{username}; # Registrant's Profile User Name<br />

my $password = $in{password}; # Registrant's Profile Password<br />

# Set Up Output Acceptance For Browser<br />

print "Content-type: text/html\n\n";<br />

# Subroutine Call To Authenticate Registrant And Generate Cookie<br />

my $cookie = create_cookie($domain,$username,$password);<br />

# <strong>XML</strong> Call For Domain Info Defined<br />

my $xml = "<br />

<br />

<br />

<br />

0.9<br />

<br />


<br />

XCP<br />

DOMAIN<br />

GET<br />

$cookie<br />

<br />

;<br />

all_info<br />

<br />

<br />

<br />

<br />

<br />

";<br />

# Connection And Post To <strong>OpenSRS</strong> <strong>API</strong> For Domain Info<br />

my $request = POST (<br />

"https://$REMOTE_HOST",<br />

'Content-Type' => 'text/xml',<br />

'X-Username' => $rspusername,<br />

'X-Signature' => md5_hex(md5_hex($xml, $private_key), $private_key),<br />

'Content' => $xml);<br />

my $response = $ua -> request($request);<br />

## Response Handling<br />

# Output from the <strong>API</strong> is provide in <strong>XML</strong>.<br />

# Two examples of outputing the response from the <strong>API</strong> follow<br />

# <strong>XML</strong> Output Of Response<br />

print "<strong>XML</strong> Output\n\n";<br />

print Dumper($response->{'_content'});<br />

# Conversion Of <strong>XML</strong> To Perl Hash<br />

# Change To <strong>XML</strong> Parser Requires Update Here<br />

my $hashresponse = $xmltohash-><strong>XML</strong>in($response->{'_content'});


# Perl Hash Output Of Response<br />

print "\n\nHash Output\n\n";<br />

print Dumper($hashresponse);<br />

# Subroutine To Generate Authentication Cookie From Registrant<br />

Credentials<br />

sub create_cookie {<br />

# Take In Registrant Credentials<br />

my ($domain, $username, $password) = @_;<br />

# Define <strong>XML</strong> For Authentication Cookie Generation<br />

my $xml = "<br />

<br />

<br />

<br />

0.9<br />

<br />

<br />

<br />

<br />

XCP<br />

cookie<br />

set<br />

<br />

<br />

$password<br />

$domain<br />

$username<br />

<br />

<br />

<br />

<br />

<br />

";<br />

# Connection And Post To <strong>OpenSRS</strong> <strong>API</strong> For Authentication Cookie


my $request = POST (<br />

"https://$REMOTE_HOST",<br />

'Content-Type' => 'text/xml',<br />

'X-Username' => $rspusername,<br />

'X-Signature' => md5_hex(md5_hex($xml, $private_key),<br />

$private_key),<br />

'Content' => $xml);<br />

my $response = $ua -> request($request);<br />

# Conversion Of <strong>XML</strong> To Perl Hash<br />

# Change To <strong>XML</strong> Parser Requires Update Here<br />

my $hashresponse = $xmltohash-><strong>XML</strong>in($response->{'_content'});<br />

# Return Of Cookie Value From Hash<br />

return ($hashresponse->{'body'}->{'data_block'}->{'dt_assoc'}-<br />

>{'item'}->{'attributes'}->{'dt_assoc'}->{'item'}->{'cookie'}-<br />

>{'content'});<br />

}<br />

PHP example<br />

<br />

<br />


LOOKUP<br />

XCP<br />

<br />

<br />

example.com<br />

<br />

<br />

<br />

<br />

<br />

';<br />

$signature = md5(md5($xml.$private_key).$private_key);<br />

$host = "horizon.opensrs.net";<br />

$port = 55443;<br />

$url = "/";<br />

$header = "";<br />

$header .= "POST $url HTTP/1.0\r\n";<br />

$header .= "Content-Type: text/xml\r\n";<br />

$header .= "X-Username: " . $username . "\r\n";<br />

$header .= "X-Signature: " . $signature . "\r\n";<br />

$header .= "Content-Length: " . strlen($xml) . "\r\n\r\n";<br />

# ssl:// requires OpenSSL to be installed<br />

$fp = fsockopen ("ssl://$host", $port, $errno, $errstr, 30);<br />

echo "";<br />

if (!$fp) {<br />

print "HTTP ERROR!";<br />

} else {<br />

# post the data to the server<br />

fputs ($fp, $header . $xml);<br />

while (!feof($fp)) {


}<br />

$res = fgets ($fp, 1024);<br />

echo htmlEntities($res);<br />

}<br />

fclose ($fp);<br />

echo "";<br />

?><br />

<br />

VB6 example<br />

Thanks to Serguei Seleznev from Softcom Technology <strong>for</strong> developing this<br />

script.<br />

This Script is using di_MD5DLL.dll from DI Management. This is free<br />

cryptographic software code that David Ireland has written or adapted in<br />

Visual Basic and ANSI C.<br />

http://www.di-mgt.com.au/crypto.html#MD5<br />

Dim ErrNumber As Long<br />

Dim ErrDescription As String<br />

Const strUserName = "RSP_USERNAME"<br />

Const strPrivateKey = "Your Private Key Go’s here”<br />

Const strURL = "https://horizon.opensrs.net:55443"<br />

Private Declare Function MakeMD5Digest Lib "di_MD5DLL.dll" _<br />

(ByVal sData As String, ByVal sDigest As String) As Long<br />

Sub Main()<br />

' POST <strong>XML</strong> document using VB6 and MS<strong>XML</strong>4(has to be installed)<br />

Dim DocToSend As MS<strong>XML</strong>2.DOMDocument<br />

Dim pFileRequest As String<br />

Dim str<strong>XML</strong> As String


On Error GoTo err_Main<br />

pFileRequest = App.Path & "\Sample.<strong>XML</strong>"<br />

str<strong>XML</strong> = ""<br />

Set DocToSend = New MS<strong>XML</strong>2.DOMDocument<br />

If Not Read<strong>XML</strong>Document(pFileRequest, DocToSend) Then<br />

MsgBox "Cannot read " & pFileRequest & vbCrLf & _<br />

ErrNumber & ", " & ErrDescription, vbCritical<br />

Exit Sub<br />

End If<br />

If SendRequest<strong>XML</strong>(DocToSend, str<strong>XML</strong>, strURL) Then<br />

MsgBox "Response has come. " & str<strong>XML</strong><br />

' here you may save to file or reload in DOMdocument to parse<br />

Else<br />

MsgBox "Cannot send " & DocToSend.xml & vbCrLf & _<br />

ErrNumber & ", " & ErrDescription, vbCritical<br />

Exit Sub<br />

End If<br />

Set DocToSend = Nothing<br />

Exit Sub<br />

err_Main:<br />

ErrNumber = Err.Number<br />

ErrDescription = "Run-time ERROR in Main. " & Err.Description<br />

MsgBox "Error " & ErrNumber & ", " & ErrDescription, vbCritical<br />

End Sub<br />

Private Function SendRequest<strong>XML</strong>( _<br />

ByRef p<strong>XML</strong>Doc As MS<strong>XML</strong>2.DOMDocument, _<br />

ByRef pcTmp As String, _<br />

ByVal pstrURL As String _


) As Boolean<br />

Dim xmlHttp As MS<strong>XML</strong>2.<strong>XML</strong>HTTP40<br />

On Error GoTo err_SendRequest<strong>XML</strong><br />

SendRequest<strong>XML</strong> = False<br />

Set xmlHttp = New MS<strong>XML</strong>2.<strong>XML</strong>HTTP40<br />

xmlHttp.Open "POST", pstrURL, False ' False - syncronous mode<br />

xmlHttp.setRequestHeader "Content-Type", "text/xml"<br />

xmlHttp.setRequestHeader "X-Username", strUserName<br />

xmlHttp.setRequestHeader "X-Signature",<br />

MD5Encode(MD5Encode(p<strong>XML</strong>Doc.xml & strPrivateKey) & strPrivateKey)<br />

xmlHttp.send p<strong>XML</strong>Doc.xml<br />

pcTmp = xmlHttp.response<strong>XML</strong>.xml<br />

Set xmlHttp = Nothing<br />

SendRequest<strong>XML</strong> = True<br />

'' 'You may try to use asyncronous post<br />

'' xmlHttp.Open "POST", pstrURL, True<br />

'' xmlHttp.setRequestHeader "Content-Type", "text/xml"<br />

'' xmlHttp.setRequestHeader "X-Username", strUserName<br />

'' xmlHttp.setRequestHeader "X-Signature",<br />

MD5Encode(MD5Encode(p<strong>XML</strong>Doc.xml & strPrivateKey) & strPrivateKey)<br />

'' xmlHttp.send p<strong>XML</strong>Doc.xml<br />

'' PauseSeconds 1 'wait<br />

'' pcTmp = ""<br />

'' If xmlHttp.readyState = 4 Then 'we got it<br />

'' If xmlHttp.Status = 200 Then<br />

''<br />

pcTmp = xmlHttp.response<strong>XML</strong>.xml<br />

''<br />

SendRequest<strong>XML</strong> = True<br />

'' End If


'' Else ' let's wait <strong>for</strong> a while<br />

'' PauseSeconds 3<br />

'' If xmlHttp.readyState = 4 Then ' check again<br />

''<br />

If xmlHttp.Status = 200 Then<br />

''<br />

cTmp = xmlHttp.response<strong>XML</strong>.xml<br />

''<br />

SendRequest<strong>XML</strong> = True<br />

''<br />

End If<br />

'' End If<br />

'' End If<br />

Exit Function<br />

err_SendRequest<strong>XML</strong>:<br />

If IsObject(xmlHttp) Then Set xmlHttp = Nothing<br />

ErrNumber = Err.Number<br />

ErrDescription = "Run-time ERROR in SendRequest<strong>XML</strong>. " &<br />

Err.Description<br />

Err.Clear<br />

End Function<br />

Private Function Read<strong>XML</strong>Document(ByVal pDocName As String, ByRef<br />

p<strong>XML</strong>Doc As MS<strong>XML</strong>2.DOMDocument) As Boolean<br />

On Error GoTo err_Read<strong>XML</strong>Document<br />

Read<strong>XML</strong>Document = False<br />

p<strong>XML</strong>Doc.async = False<br />

p<strong>XML</strong>Doc.resolveExternals = False<br />

refered DTD<br />

' otherwise you must have a


p<strong>XML</strong>Doc.validateOnParse = False ' in a same directory<br />

p<strong>XML</strong>Doc.Load pDocName<br />

If p<strong>XML</strong>Doc.parseError.errorCode = 0 Then<br />

Else<br />

Read<strong>XML</strong>Document = True<br />

ErrNumber = p<strong>XML</strong>Doc.parseError.errorCode<br />

ErrDescription = "Errors in " & p<strong>XML</strong>Doc.parseError.url & ",<br />

line " & p<strong>XML</strong>Doc.parseError.Line & ", pos " &<br />

p<strong>XML</strong>Doc.parseError.linepos<br />

ErrDescription = ErrDescription & ". Error #" & ErrNumber & ".<br />

" & p<strong>XML</strong>Doc.parseError.reason<br />

End If<br />

Exit Function<br />

err_Read<strong>XML</strong>Document:<br />

ErrNumber = Err.Number<br />

ErrDescription = "Run-time ERROR in Read<strong>XML</strong>Document " &<br />

Err.Description & " <strong>for</strong> " & pDocName<br />

Err.Clear<br />

End Function<br />

' contents of file Sample.<strong>XML</strong><br />

'<br />

'<br />

'<br />

' <br />

' 0.9<br />

' <br />

' <br />

' <br />

'<br />

<br />

'<br />

DOMAIN


'<br />

<br />

'<br />

<br />

'<br />

MyDomainToLookup.com<br />

'<br />

<br />

'<br />

<br />

'<br />

XCP<br />

'<br />

LOOKUP<br />

'<br />

<br />

' <br />

' <br />

'<br />

Public Function MD5Encode(ByVal sData As String) As String<br />

Dim iRet As Long<br />

Dim sDigest As String<br />

' Set sDigest to be 32 chars<br />

sDigest = String(32, " ")<br />

iRet = MakeMD5Digest(sData, sDigest)<br />

MD5Encode = Trim(sDigest)<br />

End Function<br />

VB .NET example<br />

Dim mypost As New <strong>OpenSRS</strong>_<strong>XML</strong>POST<br />

TextBox1.Text = mypost.sendPost(RESPONSE_TEXT)<br />

------------------<br />

Imports System.Web.Security<br />

Public Class <strong>OpenSRS</strong>_<strong>XML</strong>POST<br />

Public Const URL_BASE = "https://horizon.opensrs.net:55443"<br />

Public Const RSP_USERNAME As String = "RSP USERNAME"<br />

Public Const PRIVATE_KEY = "Enter Private Key"<br />

Public Function sendPost(ByVal str As String)<br />

Dim myHttpWebRequest As New System.Net.WebClient


myHttpWebRequest.Headers.Add("Content-Type", "text/xml")<br />

myHttpWebRequest.Headers.Add("X-Username", RSP_USERNAME)<br />

myHttpWebRequest.Headers.Add("X-Signature", cMD5(cMD5(str &<br />

PRIVATE_KEY) & PRIVATE_KEY))<br />

Dim sendData As Byte() =<br />

System.Text.Encoding.ASCII.GetBytes(str)<br />

Dim myHttpResponse As Byte() =<br />

myHttpWebRequest.UploadData(URL_BASE, "POST", sendData)<br />

Return System.Text.Encoding.ASCII.GetString(myHttpResponse)<br />

End Function<br />

'Used to convert to MD5<br />

Public Function cMD5(ByVal str As String) As String<br />

'Must have Imports System.Web.Security in General Declarations<br />

Dim Hash As String =<br />

FormsAuthentication.HashPasswordForStoringInConfigFile(str, "MD5")<br />

Return Hash.ToLower<br />

End Function<br />

End Class<br />

Java example<br />

package net.client;<br />

import javax.net.ssl.*;<br />

import javax.net.SocketFactory;<br />

import java.net.*;<br />

import java.io.InputStream;<br />

import java.io.OutputStream;<br />

import java.io.IOException;<br />

import java.security.MessageDigest;<br />

import java.util.Hashtable;<br />

import java.math.BigInteger;<br />

import org.apache.commons.httpclient.*;<br />

import org.apache.commons.httpclient.methods.PostMethod;<br />

import org.apache.commons.httpclient.protocol.*;<br />

import com.pureload.task.api.TaskExecuteException;


public class SslClient {<br />

private String privateKey;<br />

private String host;<br />

private int port;<br />

private String userName;<br />

private Header [] headers = null;<br />

public class MySSLSocketFactory implements SecureProtocolSocketFactory<br />

{<br />

private TrustManager[] getTrustManager() {<br />

TrustManager[] trustAllCerts = new TrustManager[]{<br />

new X509TrustManager() {<br />

public java.security.cert.X509Certificate[] getAcceptedIssuers() {<br />

return null;<br />

}<br />

public void checkClientTrusted(<br />

}<br />

java.security.cert.X509Certificate[] certs, String authType) {<br />

public void checkServerTrusted(<br />

}<br />

}<br />

};<br />

java.security.cert.X509Certificate[] certs, String authType) {<br />

return trustAllCerts;<br />

}<br />

public Socket createSocket(String host, int port) throws IOException,<br />

UnknownHostException {<br />

TrustManager[] trustAllCerts = getTrustManager();<br />

try {<br />

SSLContext sc = SSLContext.getInstance("SSL");<br />

sc.init(null, trustAllCerts, new java.security.SecureRandom());<br />

HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());


SocketFactory socketFactory =<br />

HttpsURLConnection.getDefaultSSLSocketFactory();<br />

return socketFactory.createSocket(host, port);<br />

}<br />

catch (Exception ex) {<br />

throw new UnknownHostException("Problems to connect " + host +<br />

ex.toString());<br />

}<br />

}<br />

public Socket createSocket(Socket socket, String host, int port,<br />

boolean flag) throws IOException, UnknownHostException {<br />

TrustManager[] trustAllCerts = getTrustManager();<br />

try {<br />

SSLContext sc = SSLContext.getInstance("SSL");<br />

sc.init(null, trustAllCerts, new java.security.SecureRandom());<br />

HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());<br />

SocketFactory socketFactory =<br />

HttpsURLConnection.getDefaultSSLSocketFactory();<br />

return socketFactory.createSocket(host, port);<br />

}<br />

catch (Exception ex) {<br />

throw new UnknownHostException("Problems to connect " + host +<br />

ex.toString());<br />

}<br />

}<br />

public Socket createSocket(String host, int port, InetAddress<br />

clientHost, int clientPort) throws IOException, UnknownHostException {<br />

TrustManager[] trustAllCerts = getTrustManager();<br />

try {<br />

SSLContext sc = SSLContext.getInstance("SSL");<br />

sc.init(null, trustAllCerts, new java.security.SecureRandom());<br />

HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());<br />

SocketFactory socketFactory =<br />

HttpsURLConnection.getDefaultSSLSocketFactory();<br />

return socketFactory.createSocket(host, port, clientHost, clientPort);


}<br />

catch (Exception ex) {<br />

throw new UnknownHostException("Problems to connect " + host +<br />

ex.toString());<br />

}<br />

}<br />

}<br />

public SslClient(String host, int port, String userName, String<br />

privateKey) {<br />

this.host=host;<br />

this.port = port;<br />

this.userName = userName;<br />

this.privateKey = privateKey;<br />

}<br />

protected String md5Sum(String str) {<br />

String sum = new String();<br />

try {<br />

MessageDigest md5 = MessageDigest.getInstance("MD5");<br />

sum = String.<strong>for</strong>mat("%032x", new BigInteger(1,<br />

md5.digest(str.getBytes())));<br />

}<br />

} catch (Exception ex) {<br />

}<br />

return sum;<br />

public String getSignature(String xml) {<br />

}<br />

return md5Sum(md5Sum(xml + privateKey) + privateKey);<br />

public String sendRequest(String xml) throws TaskExecuteException {<br />

HttpClient client = new HttpClient();<br />

client.setConnectionTimeout(60000);<br />

client.setTimeout(60000);


String response = new String();<br />

String portStr = String.valueOf(port);<br />

Protocol.registerProtocol("https", new Protocol("https", new<br />

MySSLSocketFactory(), port));<br />

String signature = getSignature(xml);<br />

String uri = "https://" + host + ":" + portStr + "/";<br />

PostMethod postRequest = new PostMethod(uri);<br />

postRequest.addRequestHeader("Content-Length",<br />

String.valueOf(xml.length()));<br />

postRequest.addRequestHeader("Content-Type", "text/xml");<br />

postRequest.addRequestHeader("X-Signature", signature);<br />

postRequest.addRequestHeader("X-Username", userName);<br />

postRequest.setRequestBody(xml);<br />

System.out.println("Sending https request....."+postRequest.<br />

toString());<br />

try {<br />

client.executeMethod(postRequest);<br />

}<br />

catch (Exception ex) {<br />

throw new TaskExecuteException("Sending post got exception ", ex);<br />

}<br />

response = postRequest.getResponseBodyAsString();<br />

headers = postRequest.getRequestHeaders();<br />

return response;<br />

}<br />

public String getPrivateKey() {<br />

return privateKey;<br />

}<br />

public void setPrivateKey(String privateKey) {<br />

this.privateKey = privateKey;<br />

}<br />

public String getHost() {<br />

return host;


}<br />

public void setHost(String host) {<br />

this.host = host;<br />

}<br />

public int getPort() {<br />

return port;<br />

}<br />

public void setPort(int port) {<br />

this.port = port;<br />

}<br />

public String getUserName() {<br />

return userName;<br />

}<br />

public void setUserName(String userName) {<br />

this.userName = userName;<br />

}<br />

public Header[] getHeaders() {<br />

return headers;<br />

}<br />

public void setHeaders(Header[] headers) {<br />

this.headers = headers;<br />

}<br />

public static void main(String[] args) {<br />

String privateKey = "your_private_key";<br />

String userName = "your_user_name";<br />

String host="horizon.opensrs.net";<br />

int port = 55443;<br />

String xml=<br />

""+


""+<br />

""+<br />

""+<br />

"0.9"+<br />

"2.21765911726198"+<br />

"standard"+<br />

""+<br />

""+<br />

""+<br />

""+<br />

""+<br />

""+<br />

"test-1061911771844.com"+<br />

"0"+<br />

""+<br />

""+<br />

"DOMAIN"+<br />

"LOOKUP"+<br />

"XCP"+<br />

""+<br />

""+<br />

""+<br />

"";<br />

SslClient sslclient = new SslClient(host,port,userName,privateKey);<br />

try {<br />

String response = sslclient.sendRequest(xml);<br />

System.out.println("\nResponse is:\n"+response);<br />

}


catch (TaskExecuteException e) {<br />

}<br />

e.printStackTrace();<br />

}<br />

}<br />

Data exchange<br />

For each line of data passed, you must prepend the data with the length of<br />

the string packed in 'network' or big-endian order. In Perl, this is<br />

accomplished by:<br />

$length = pack('n', length($data));<br />

Where $data is the in<strong>for</strong>mation you are going to send.<br />

For example, assuming you have a socket SERVER already open to the<br />

server process, you could send data as follows:<br />

print SERVER pack('n', length($data));<br />

print SERVER $data;<br />

Since you must always send the length of the string first, it will not work to<br />

simply telnet to the <strong>OpenSRS</strong> server and begin issuing commands.<br />

Authentication handshake<br />

The first step in communicating with the server process is the authentication<br />

handshake. This proceeds between the Reseller Client and Reseller Agent<br />

(server) as follows:<br />

Process<br />

Description<br />

1 Reseller Client Initiates connection with Reseller Agent (server<br />

process) on a specific TCP/IP hostname:port.<br />

Horizon: horizon.opensrs.net:55000<br />

Live: rr-n1-tor.opensrs.net:55000


Process Description<br />

2 Reseller Agent Server sends an XCP 'check version' request.<br />

Perl Example (hash):<br />

{<br />

}<br />

'protocol' => 'XCP',<br />

'action' => 'check',<br />

'object' => 'version',<br />

'attributes' => {<br />

}<br />

'sender' => '<strong>OpenSRS</strong> SERVER',<br />

'version' => '$VERSION',<br />

'state' => 'ready'<br />

The values of $VERSION could be something such as<br />

'<strong>XML</strong>:0.1', which indicates the language spoken and<br />

the minimum version of the client required by this<br />

RSA. At this point, the only value <strong>for</strong> 'state' is 'ready'.<br />

Other states may be added in the future.<br />

3 Reseller Client Client responds with an XCP 'check version' response<br />

(where version is the client's protocol version.)<br />

Note: This number should not be changed. It allows<br />

<strong>for</strong> <strong>API</strong> changes and backward compatibility. If you<br />

change the version number of the client, results may<br />

be unpredictable.<br />

Perl Example (hash):<br />

{<br />

}<br />

'protocol' => 'XCP',<br />

'action' => 'check',<br />

'object' => 'version',<br />

'attributes' => {<br />

'sender' => '<strong>OpenSRS</strong> CLIENT',<br />

'version' => '<strong>XML</strong>:0.1',<br />

'state' => 'ready',<br />

}


Process Description<br />

The only difference here is the value of the sender<br />

attribute. Again, the only valid state at this point is<br />

'ready'.<br />

4 Reseller Client Client sends user data <strong>for</strong> authentication. This is done<br />

using the XCP 'authenticate user' request.<br />

Note: As a Reseller, you have a password and a<br />

username. Do NOT send the password in this request,<br />

it is not needed. The current <strong>XML</strong> Perl Client actually<br />

sends the username in both the username and<br />

password fields. This is because the data packets are<br />

not encrypted at this stage of the transmission.<br />

Perl Example (hash):<br />

{<br />

}<br />

'protocol' => 'XCP',<br />

'action' => 'authenticate',<br />

'object' => 'user',<br />

'attributes' => {<br />

}<br />

'crypt_type' => '',<br />

'username' => '',<br />

'password' => ''<br />

The crypt_type can be either 'des' or 'blowfish'.<br />

5 Reseller Agent If authentication is successful, the Reseller Agent<br />

(server side), sends the first challenge, but without<br />

<strong>XML</strong>. The challenge is a random number of random<br />

bits.<br />

6 Reseller Client Reseller Client The client returns the challenge's md5<br />

checksum, encrypted with the Reseller's private key<br />

and without <strong>XML</strong>.<br />

7 Reseller Agent If the challenge is successful, the Reseller Agent<br />

(server) replies with an XCP 'authenticate user'<br />

response.<br />

Perl Example (hash):<br />

{<br />

'protocol' => 'XCP',


Process Description<br />

'action' => 'reply',<br />

'response_code' => '200',<br />

'response_text' => 'Authentication<br />

Successful'<br />

}<br />

If the Reseller Agent deems that the Reseller Client has<br />

failed the challenge, it closes the socket without<br />

sending a decline reply because it is assumed that the<br />

Reseller Client cannot understand any of the encrypted<br />

messages anyway.<br />

Another possible response code would be code 310, if<br />

the Reseller's command rate is exceeded.<br />

8 Reseller Client If the Reseller Client receives a response code of 200,<br />

it can then send its first XCP command. All further<br />

communication <strong>for</strong> the established session is<br />

encrypted.<br />

The first XCP command the client must send after<br />

being authenticated is 'set cookie'. This is required<br />

because the cookie is used <strong>for</strong> all further authenticated<br />

commands.<br />

Encryption<br />

Supported ciphers<br />

<strong>OpenSRS</strong> currently supports the DES and Blowfish encryption algorithms.<br />

The suggested method of using these encryption types is through their<br />

respective Perl modules, Crypt::DES and Crypt::Blowfish, which are then<br />

accessed through a common interface created by Crypt::CBC. For your<br />

convenience, Crypt::CBC is now included in the <strong>OpenSRS</strong> client distribution.<br />

If you are unable to install Crypt::DES or Crypt::Blowfish there is a third<br />

option available: Crypt::Blowfish_PP, which is a module <strong>for</strong> Blowfish written<br />

in Pure Perl (PP). Our initial testing has shown this module to be at least 10<br />

times slower than the standard Crypt::Blowfish, but it may be used as a last<br />

resort.


Private key<br />

DES only supports keys of 8 bytes, while Blowfish supports keys of up to 56<br />

bytes <strong>for</strong> greater security.<br />

Private keys in <strong>OpenSRS</strong> are 112 characters in length (56 bytes), to provide<br />

the maximum security <strong>for</strong> people using Blowfish. If you are an existing<br />

customer and you are using an old key (8 bytes), you will not be able to use<br />

the Blowfish cipher until you generate a new key. We recommend that you<br />

generate a new private key to ensure the strongest encryption possible. Old<br />

keys were 8 bytes in length and new keys are 56 bytes in length.<br />

You can continue using the (old) 8-byte key if you only wish to use DES as<br />

your cipher. Even if you have a new key (56 bytes), you can still use it with<br />

the DES cipher, since Crypt::CBC only uses the portion of the private key<br />

that is needed (in the case of DES, it simply ignores everything after the first<br />

8 bytes).<br />

When creating your encryption cipher, do not use the private key in raw<br />

<strong>for</strong>m. Instead, first pack the key into a hexadecimal binary string. In Perl this<br />

is accomplished with:<br />

$private_key = pack('H*', $private_key);<br />

You may then use the private key to create your encryption cipher,<br />

authenticate, and begin sending data to the server.<br />

Reseller Agent Return Codes<br />

Code<br />

200<br />

Response text / Explanation<br />

Command Successful.<br />

Authentication Successful.<br />

Closing Connection.<br />

Registration Successful.<br />

Modification Successful.<br />

Nameserver Update Successful.<br />

Nameserver Added.<br />

Nameserver Created.<br />

Nameserver deleted.<br />

No nameserver changes necessary.<br />

Query Successful.<br />

Registration successful.


Code<br />

Response text / Explanation<br />

210 Domain available.<br />

211 Domain taken.<br />

221<br />

250<br />

Domain taken (a waiting registration exists in <strong>OpenSRS</strong>).<br />

Note: This is used <strong>for</strong> asynchronous registries only.<br />

Action submitted successfully <strong>for</strong> processing to asynchronous<br />

registry.<br />

300 Exceeded max command rate. Request deferred (<strong>for</strong> asynch).<br />

310 Exceeded max simultaneous connections.<br />

350<br />

400<br />

Number of command per connection exceeded limit. Client must reauthenticate<br />

with server.<br />

A maximum of 100 commands can be sent through one<br />

connection/session. After 100 commands have been submitted, the<br />

connection is closed and a new connection must be opened to submit<br />

outstanding requests.<br />

Internal server error.<br />

Invalid Command: xxx.<br />

Access denied: invalid IP address.<br />

Invalid encryption method; try -des: ...<br />

Unable to change nameserver hostname to $new_fqdn.<br />

Unable to complete registration. Please retry.<br />

Domain already renewed; another renewal cannot be applied until<br />

the first request completes at the registry.<br />

404 Internal Server Error.<br />

405<br />

Registry error: domain's nameserver not updated.<br />

Registry error, unable to add nameserver to domain.<br />

Registry error, unable to remove nameserver.<br />

Registry error, nameserver creation failed.<br />

Nameserver deletion failed at registry.<br />

Unable to modify nameserver record.<br />

410 Reseller authentication error.


Code<br />

415<br />

Response text / Explanation<br />

Registrant (end-user) authentication error.<br />

Invalid Cookie Supplied.<br />

Invalid Password supplied.<br />

430 Invalid command.<br />

435<br />

436<br />

437<br />

Permission denied, subuser permissions.<br />

Permission Denied <strong>for</strong> Modify $type, f_owner=xxx<br />

#modify_contact_info.<br />

Cannot remove domain owner.<br />

Permission Denied: not owner.<br />

Request failed validation: Name server 'nameserver.tld' is not found<br />

at the registry. Please double check the nameserver and re-submit.<br />

This error occurs when the RM does not know what to do with the<br />

response code returned by the RA after it talked with the registry.<br />

This error usually means that the RM needs to be fixed to understand<br />

the new response.<br />

Cannot process command because there is already another request<br />

waiting on this domain. (Used <strong>for</strong> asynchronous registries.)<br />

440 Registration Failed: over quota.<br />

445 Nameserver quota exceeded.<br />

447 Sub-user limit exceeded.<br />

460<br />

No Cookie Supplied.<br />

No Domain Supplied.<br />

Modify type not specified.<br />

Required field 'username' not provided.<br />

Required field 'password' not provided.<br />

Missing required field.<br />

Missing required field: fqdn.<br />

Missing required field: ip.<br />

Info type not specified.<br />

Required field 'reg_username' not provided.<br />

Required field 'reg_password' not provided.<br />

465 Registration Failed: Invalid data, error=<br />

Registration Failed, error=


Code<br />

Response text / Explanation<br />

Unknown Modify type: xxx<br />

Invalid data, error=#modify_contact_info.<br />

Subuser cannot be the same as the owner.<br />

Invalid syntax <strong>for</strong> subuser name.<br />

Password exceeded maximum length: 20 characters.<br />

Invalid domain name syntax.<br />

Invalid syntax <strong>for</strong> registrant username.<br />

Password length below minimum: 3 characters.<br />

Invalid nameserver syntax (common_rule <strong>for</strong> nameserver).<br />

Invalid syntax <strong>for</strong> nameserver (2nd level domain).<br />

Invalid new nameserver hostname.<br />

Invalid domain name syntax.<br />

Duplicate nameserver detected <strong>for</strong> xxx.<br />

Duplicate sortorder detected <strong>for</strong> xxx.<br />

Invalid IP address: $ip<br />

Unknown Info type: $type'<br />

Invalid syntax <strong>for</strong> username.<br />

Invalid registration type: $reg_type<br />

Domain does not belong to Registrar<br />

480<br />

Domain xxx not owned by user.<br />

Renewals not supported <strong>for</strong> this TLD. Response text =<br />

'capability is not enabled <strong>for</strong> domain.ca'.<br />

Cookie not found.<br />

Subuser not found.<br />

Subuser xxx not found.<br />

Sub-User not found.<br />

User profile <strong>for</strong> xxx/xxx not found.<br />

Profile based on xxx not found.<br />

Command failed: unable to verify existence of nameserver xxx.<br />

Nameserver doesn't exist.<br />

Unable to locate nameserver in local database.<br />

Unable to find domain in registry.<br />

Nameserver $fqdn not currently mapped to domain.<br />

Nameserver not found.


Code<br />

Response text / Explanation<br />

Non-existent nameserver #(in registry).<br />

485<br />

486<br />

Domain taken.<br />

Nameserver already mapped to domain.<br />

Nameserver $fqdn already exists (as result of request in DB or RRP).<br />

Nameserver in use.<br />

New nameserver hostname already in registry.<br />

Entity already exists in a processing state (usually a domain<br />

registration) Trying again in a few seconds to a minute should resolve<br />

the issue (i.e. show it truly taken or available).<br />

487 Domain not transferable.<br />

541<br />

552<br />

555<br />

557<br />

Domain's current expiration year in registry doesn't match the year<br />

provided by user.<br />

Domain is less than 60 days old.<br />

This can occur if:<br />

• domain is not yet 60 days old.<br />

• existing registrar has the name locked <strong>for</strong> either nonpayment or at<br />

the end users request - requesting party needs to contact existing<br />

registrar to resolve.<br />

• domain name is in dispute.<br />

• the name has been deleted.<br />

Domain has already been successfully renewed, with the current<br />

expiration year matching the year provided by the user.<br />

Nameserver locked.<br />

An attempt has been made to modify or delete a name server that is<br />

hosting a TLD in the root zone. Modifications to the root zone can<br />

only be made with the approval of the U.S. Department of Commerce<br />

and IANA, so if the registrar absolutely needs to modify or delete<br />

such a name server; the action needs to be coordinated through the<br />

registry operator using an out-of-band communications channel.<br />

(Extracted from the RRP spec.)<br />

702 Catch all code <strong>for</strong> errors related to communication issues.<br />

703 Could not send command.<br />

704 Read empty message on the socket.


Code<br />

705<br />

Response text / Explanation<br />

Timed out, resubmit request.<br />

Client timed out waiting <strong>for</strong> the RA to respond.<br />

unnumbered<br />

Domain: Registration attempt failed: Timeout<br />

reading client request. Client must re-authenticate with server.<br />

A connection with the <strong>OpenSRS</strong>

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!