package org.bouncycastle.crypto.tls;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Hashtable;

import org.bouncycastle.util.Integers;

public class TlsExtensionsUtils
{
    public static final Integer EXT_server_name = Integers.valueOf(ExtensionType.server_name);
    public static final Integer EXT_status_request = Integers.valueOf(ExtensionType.status_request);

    public static void addServerNameExtension(Hashtable extensions, ServerNameList serverNameList)
        throws IOException
    {
        extensions.put(EXT_server_name, createServerNameExtension(serverNameList));
    }

    public static void addStatusRequestExtension(Hashtable extensions, CertificateStatusRequest statusRequest)
        throws IOException
    {
        extensions.put(EXT_status_request, createStatusRequestExtension(statusRequest));
    }

    public static ServerNameList getServerNameExtension(Hashtable extensions)
        throws IOException
    {
        byte[] extensionData = TlsUtils.getExtensionData(extensions, EXT_server_name);
        return extensionData == null ? null : readServerNameExtension(extensionData);
    }

    public static CertificateStatusRequest getStatusRequestExtension(Hashtable extensions)
        throws IOException
    {
        byte[] extensionData = TlsUtils.getExtensionData(extensions, EXT_status_request);
        return extensionData == null ? null : readStatusRequestExtension(extensionData);
    }

    public static byte[] createServerNameExtension(ServerNameList serverNameList)
        throws IOException
    {
        if (serverNameList == null)
        {
            throw new TlsFatalAlert(AlertDescription.internal_error);
        }
        
        ByteArrayOutputStream buf = new ByteArrayOutputStream();
        
        serverNameList.encode(buf);

        return buf.toByteArray();
    }

    public static byte[] createStatusRequestExtension(CertificateStatusRequest statusRequest)
        throws IOException
    {
        if (statusRequest == null)
        {
            throw new TlsFatalAlert(AlertDescription.internal_error);
        }

        ByteArrayOutputStream buf = new ByteArrayOutputStream();

        statusRequest.encode(buf);

        return buf.toByteArray();
    }

    public static ServerNameList readServerNameExtension(byte[] extensionData)
        throws IOException
    {
        if (extensionData == null)
        {
            throw new IllegalArgumentException("'extensionData' cannot be null");
        }

        ByteArrayInputStream buf = new ByteArrayInputStream(extensionData);

        ServerNameList serverNameList = ServerNameList.parse(buf);

        TlsProtocol.assertEmpty(buf);

        return serverNameList;
    }

    public static CertificateStatusRequest readStatusRequestExtension(byte[] extensionData)
        throws IOException
    {
        if (extensionData == null)
        {
            throw new IllegalArgumentException("'extensionData' cannot be null");
        }

        ByteArrayInputStream buf = new ByteArrayInputStream(extensionData);

        CertificateStatusRequest statusRequest = CertificateStatusRequest.parse(buf);

        TlsProtocol.assertEmpty(buf);

        return statusRequest;
    }
}

@@ -445,16 +445,118 @@
 quest);%0D
+%0A    public static final Integer EXT_truncated_hmac = Integers.valueOf(ExtensionType.truncated_hmac);%0D
 %0A%0D%0A    p
@@ -1017,32 +1017,197 @@
 st));%0D%0A    %7D%0D%0A%0D%0A
+    public static void addTruncatedHMacExtension(Hashtable extensions)%0D%0A    %7B%0D%0A        extensions.put(EXT_truncated_hmac, createTruncatedHMacExtension());%0D%0A    %7D%0D%0A%0D%0A
     public stati
@@ -1797,32 +1797,431 @@
 ata);%0D%0A    %7D%0D%0A%0D%0A
+    public static boolean hasTruncatedHMacExtension(Hashtable extensions) throws IOException%0D%0A    %7B%0D%0A        byte%5B%5D extensionData = TlsUtils.getExtensionData(extensions, EXT_truncated_hmac);%0D%0A        return extensionData == null ? false : readTruncatedHMacExtension(extensionData);%0D%0A    %7D%0D%0A%0D%0A    public static byte%5B%5D createEmptyExtensionData()%0D%0A    %7B%0D%0A        return TlsUtils.EMPTY_BYTES;%0D%0A    %7D%0D%0A%0D%0A
     public stati
@@ -3024,32 +3024,149 @@
 ay();%0D%0A    %7D%0D%0A%0D%0A
+    public static byte%5B%5D createTruncatedHMacExtension()%0D%0A    %7B%0D%0A        return createEmptyExtensionData();%0D%0A    %7D%0D%0A%0D%0A
     public stati
@@ -4110,32 +4110,32 @@
 tEmpty(buf);%0D%0A%0D%0A
-
         return s
@@ -4155,12 +4155,427 @@
 %0D%0A    %7D%0D
+%0A%0D%0A    private static boolean readTruncatedHMacExtension(byte%5B%5D extensionData) throws IOException%0D%0A    %7B%0D%0A        if (extensionData == null)%0D%0A        %7B%0D%0A            throw new IllegalArgumentException(%22'extensionData' cannot be null%22);%0D%0A        %7D%0D%0A%0D%0A        if (extensionData.length != 0)%0D%0A        %7B%0D%0A            throw new TlsFatalAlert(AlertDescription.illegal_parameter);%0D%0A        %7D%0D%0A%0D%0A        return true;%0D%0A    %7D%0D
 %0A%7D%0D%0A

Add support methods for truncated_hmac extension